From d4f3614dd9706f6ec0128c58a78d3c0555668d6f Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 20:47:18 -0700 Subject: [PATCH 1/9] Added scoped storage to env --- buildcc/lib/env/include/env/storage.h | 97 +++++++++++++++++++++++++++ buildcc/lib/env/test/test_storage.cpp | 64 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 buildcc/lib/env/include/env/storage.h create mode 100644 buildcc/lib/env/test/test_storage.cpp diff --git a/buildcc/lib/env/include/env/storage.h b/buildcc/lib/env/include/env/storage.h new file mode 100644 index 00000000..ebc611f3 --- /dev/null +++ b/buildcc/lib/env/include/env/storage.h @@ -0,0 +1,97 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ENV_STORAGE_H_ +#define ENV_STORAGE_H_ + +#include +#include +#include +#include + +#include "env/assert_fatal.h" + +#include "fmt/format.h" + +namespace buildcc { + +class ScopedStorage { +public: + ScopedStorage() {} + ~ScopedStorage() { + for (const auto &ptr_iter : ptrs_) { + ptr_iter.second.destructor(); + } + ptrs_.clear(); + env::assert_fatal(ptrs_.empty(), "Memory not deallocated"); + } + + ScopedStorage(const ScopedStorage &) = delete; + + template + T &Add(const std::string &identifier, Params &&...params) { + T *ptr = new T(std::forward(params)...); + env::assert_fatal(ptr != nullptr, "System out of memory"); + + PtrMetadata metadata; + metadata.ptr = (void *)ptr; + metadata.typeid_name = typeid(T).name(); + metadata.destructor = [this, identifier, ptr]() { + env::log_trace("Cleaning", identifier); + Remove(ptr); + }; + ptrs_.emplace(identifier, metadata); + return *ptr; + } + + template void Remove(T *ptr) { delete ptr; } + + template const T &ConstRef(const std::string &identifier) const { + const PtrMetadata &metadata = ptrs_.at(identifier); + env::assert_fatal( + typeid(T).name() == metadata.typeid_name, + fmt::format("Wrong type, expects: {}", metadata.typeid_name)); + const T *p = (const T *)metadata.ptr; + return *p; + } + + // https://stackoverflow.com/questions/123758/how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-func/123995 + template T &Ref(const std::string &identifier) { + return const_cast( + static_cast(*this).ConstRef(identifier)); + } + +private: + /** + * @brief + * @param ptr Can hold data of any type + * @param typeid_name We cannot store a template type so this is the next best + * thing + * @param desstructor Destructor callback to delete ptr + */ + struct PtrMetadata { + void *ptr; + std::string typeid_name; + std::function destructor; + }; + +private: + std::unordered_map ptrs_; +}; + +} // namespace buildcc + +#endif diff --git a/buildcc/lib/env/test/test_storage.cpp b/buildcc/lib/env/test/test_storage.cpp new file mode 100644 index 00000000..72fbb230 --- /dev/null +++ b/buildcc/lib/env/test/test_storage.cpp @@ -0,0 +1,64 @@ +#include "env/storage.h" + +// NOTE, Make sure all these includes are AFTER the system and header includes +#include "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/MemoryLeakDetectorNewMacros.h" +#include "CppUTest/TestHarness.h" +#include "CppUTest/Utest.h" +#include "CppUTestExt/MockSupport.h" + +// clang-format off +TEST_GROUP(ScopedStorageTestGroup) +{ +}; +// clang-format on + +class BigObj {}; + +class BigObjWithParameters { +public: + BigObjWithParameters(const std::string &name, int id, const BigObj &obj) { + (void)name; + (void)id; + (void)obj; + } + + std::string GetName() const { return __FUNCTION__; } +}; + +static BigObj obj; + +TEST(ScopedStorageTestGroup, BasicUsage) { + buildcc::ScopedStorage storage; + storage.Add("identifier", "name", 10, obj); + storage.Add("identifier2", "name2", 12, obj); + + // Usage + storage.ConstRef("identifier").GetName(); + storage.Ref("identifier2").GetName(); + + // Automatic cleanup here +} + +TEST(ScopedStorageTestGroup, IncorrectUsage) { + buildcc::ScopedStorage storage; + storage.Add("identifier", "name", 10, obj); + + // We try to cast to a different type! + CHECK_THROWS(std::exception, storage.Ref("identifier")); + + // We use a wrong identifier + CHECK_THROWS(std::exception, + storage.Ref("identifier2")); +} + +std::string &toReference(std::string *pointer) { return *pointer; } + +TEST(ScopedStorageTestGroup, NullptrDelete) { + buildcc::ScopedStorage storage; + storage.Remove(nullptr); +} + +int main(int ac, char **av) { + return CommandLineTestRunner::RunAllTests(ac, av); +} From 44774b816f9b144dd4772901492a15848889d14e Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 20:47:34 -0700 Subject: [PATCH 2/9] Added unit tests --- buildcc/lib/env/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildcc/lib/env/CMakeLists.txt b/buildcc/lib/env/CMakeLists.txt index f76bcc34..f0225e7c 100644 --- a/buildcc/lib/env/CMakeLists.txt +++ b/buildcc/lib/env/CMakeLists.txt @@ -38,10 +38,14 @@ if (${TESTING}) add_executable(test_command test/test_command.cpp) target_link_libraries(test_command PRIVATE mock_env) + add_executable(test_storage test/test_storage.cpp) + target_link_libraries(test_storage PRIVATE mock_env) + add_test(NAME test_static_project COMMAND test_static_project) add_test(NAME test_env_util COMMAND test_env_util) add_test(NAME test_task_state COMMAND test_task_state) add_test(NAME test_command COMMAND test_command) + add_test(NAME test_storage COMMAND test_storage) endif() set(ENV_SRCS From b8bbb745be49401b5427404c963f8e675fed0f14 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:30:37 -0700 Subject: [PATCH 3/9] Added storage static class --- buildcc/lib/env/CMakeLists.txt | 4 ++++ buildcc/lib/env/include/env/storage.h | 29 +++++++++++++++++++++++++++ buildcc/lib/env/src/storage.cpp | 23 +++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 buildcc/lib/env/src/storage.cpp diff --git a/buildcc/lib/env/CMakeLists.txt b/buildcc/lib/env/CMakeLists.txt index f0225e7c..f18d6b24 100644 --- a/buildcc/lib/env/CMakeLists.txt +++ b/buildcc/lib/env/CMakeLists.txt @@ -6,6 +6,7 @@ if (${TESTING}) src/env.cpp src/task_state.cpp + src/storage.cpp src/command.cpp mock/execute.cpp @@ -68,6 +69,9 @@ set(ENV_SRCS src/command.cpp src/execute.cpp include/env/command.h + + src/storage.cpp + include/env/storage.h ) if(${BUILDCC_BUILD_AS_SINGLE_LIB}) diff --git a/buildcc/lib/env/include/env/storage.h b/buildcc/lib/env/include/env/storage.h index ebc611f3..ccd1d1c9 100644 --- a/buildcc/lib/env/include/env/storage.h +++ b/buildcc/lib/env/include/env/storage.h @@ -18,6 +18,7 @@ #define ENV_STORAGE_H_ #include +#include #include #include #include @@ -92,6 +93,34 @@ class ScopedStorage { std::unordered_map ptrs_; }; +class Storage { +public: + Storage() = delete; + Storage(const Storage &) = delete; + Storage(Storage &&) = delete; + + static void Init() { internal_ = std::make_unique(); } + static void Deinit() { internal_.reset(nullptr); } + + template + static T &Add(const std::string &identifier, Params &&...params) { + return internal_->Add(identifier, + std::forward(params)...); + } + + template + static const T &ConstRef(const std::string &identifier) { + return internal_->ConstRef(identifier); + } + + template static T &Ref(const std::string &identifier) { + return internal_->Ref(identifier); + } + +private: + static std::unique_ptr internal_; +}; + } // namespace buildcc #endif diff --git a/buildcc/lib/env/src/storage.cpp b/buildcc/lib/env/src/storage.cpp new file mode 100644 index 00000000..37bae38b --- /dev/null +++ b/buildcc/lib/env/src/storage.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2021-2022 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "env/storage.h" + +namespace buildcc { + +std::unique_ptr Storage::internal_; + +} From 38c5f7c7c2f170b3bc3e025d310dc8ea249ab39a Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:30:52 -0700 Subject: [PATCH 4/9] Updated test_storaget.cpp --- buildcc/lib/env/test/test_storage.cpp | 33 ++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/buildcc/lib/env/test/test_storage.cpp b/buildcc/lib/env/test/test_storage.cpp index 72fbb230..ccd4be83 100644 --- a/buildcc/lib/env/test/test_storage.cpp +++ b/buildcc/lib/env/test/test_storage.cpp @@ -11,19 +11,32 @@ TEST_GROUP(ScopedStorageTestGroup) { }; + +TEST_GROUP(StorageTestGroup) +{ + void setup() { + buildcc::Storage::Init(); + } + void teardown() { + buildcc::Storage::Deinit(); + } +}; // clang-format on class BigObj {}; class BigObjWithParameters { public: - BigObjWithParameters(const std::string &name, int id, const BigObj &obj) { - (void)name; + BigObjWithParameters(const std::string &name, int id, const BigObj &obj) + : name_(name) { (void)id; (void)obj; } - std::string GetName() const { return __FUNCTION__; } + const std::string &GetName() const { return name_; } + +private: + std::string name_; }; static BigObj obj; @@ -59,6 +72,20 @@ TEST(ScopedStorageTestGroup, NullptrDelete) { storage.Remove(nullptr); } +TEST(StorageTestGroup, BasicUsage) { + buildcc::Storage::Add("identifier", "name", 10, obj); + buildcc::Storage::Add("identifier2", "name2", 12, obj); + + // Usage + const auto &bigobj = + buildcc::Storage::ConstRef("identifier").GetName(); + const auto &bigobj2 = + buildcc::Storage::Ref("identifier2").GetName(); + + STRCMP_EQUAL(bigobj.c_str(), "name"); + STRCMP_EQUAL(bigobj2.c_str(), "name2"); +} + int main(int ac, char **av) { return CommandLineTestRunner::RunAllTests(ac, av); } From 36e954e762ee7ef605362e53ed9963cde6c194be Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:31:42 -0700 Subject: [PATCH 5/9] Update buildcc.h --- buildcc/buildcc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildcc/buildcc.h b/buildcc/buildcc.h index 0959cea4..227d9ce0 100644 --- a/buildcc/buildcc.h +++ b/buildcc/buildcc.h @@ -27,6 +27,7 @@ #include "env/host_compiler.h" #include "env/util.h" #include "env/command.h" +#include "env/storage.h" // Base #include "toolchain/toolchain.h" @@ -57,6 +58,5 @@ // BuildCC Modules #include "args/args.h" #include "args/register.h" -#include "args/persistent_storage.h" #endif From b7397e7d62d1e848e06da54827979a00cc22c438 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:32:21 -0700 Subject: [PATCH 6/9] Removed test_persistent_storage --- buildcc/lib/args/CMakeLists.txt | 8 --- .../lib/args/test/test_persistent_storage.cpp | 60 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 buildcc/lib/args/test/test_persistent_storage.cpp diff --git a/buildcc/lib/args/CMakeLists.txt b/buildcc/lib/args/CMakeLists.txt index 5b5843fa..c0bdc98b 100644 --- a/buildcc/lib/args/CMakeLists.txt +++ b/buildcc/lib/args/CMakeLists.txt @@ -41,20 +41,12 @@ target_link_libraries(test_register PRIVATE mock_args ) -add_executable(test_persistent_storage - test/test_persistent_storage.cpp -) -target_link_libraries(test_persistent_storage PRIVATE mock_args) - add_test(NAME test_args COMMAND test_args WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test ) add_test(NAME test_register COMMAND test_register WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test ) -add_test(NAME test_persistent_storage COMMAND test_persistent_storage - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test -) endif() set(ARGS_SRCS diff --git a/buildcc/lib/args/test/test_persistent_storage.cpp b/buildcc/lib/args/test/test_persistent_storage.cpp deleted file mode 100644 index 56163d43..00000000 --- a/buildcc/lib/args/test/test_persistent_storage.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "args/persistent_storage.h" - -#include "target/generator.h" -#include "target/target.h" - -// NOTE, Make sure all these includes are AFTER the system and header includes -#include "CppUTest/CommandLineTestRunner.h" -#include "CppUTest/MemoryLeakDetectorNewMacros.h" -#include "CppUTest/TestHarness.h" -#include "CppUTest/Utest.h" -#include "CppUTestExt/MockSupport.h" - -// clang-format off -TEST_GROUP(PersistentStorageTestGroup) -{ -}; -// clang-format on - -static buildcc::BaseToolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", - "g++", "ar", "ld"); - -TEST(PersistentStorageTestGroup, BasicUsage) { - buildcc::PersistentStorage persistent; - persistent.Add("target_identifier", "target_name", - buildcc::TargetType::Executable, gcc, ""); - persistent.Add("generator_identifier", - "generator_name", ""); - - // Usage - persistent.ConstRef("target_identifier").GetName(); - persistent.Ref("generator_identifier").GetTaskflow(); - - // Automatic cleanup here -} - -TEST(PersistentStorageTestGroup, IncorrectUsage) { - buildcc::PersistentStorage persistent; - persistent.Add("target_identifier", "target_name", - buildcc::TargetType::Executable, gcc, ""); - - // We try to cast to a different type! - CHECK_THROWS(std::exception, - persistent.Ref("target_identifier")); - - // We use a wrong identifier - CHECK_THROWS(std::exception, - persistent.Ref("generator_identifier")); -} - -std::string &toReference(std::string *pointer) { return *pointer; } - -TEST(PersistentStorageTestGroup, NullptrDelete) { - buildcc::PersistentStorage persistent; - persistent.Remove(nullptr); -} - -int main(int ac, char **av) { - buildcc::Project::Init(fs::current_path(), fs::current_path()); - return CommandLineTestRunner::RunAllTests(ac, av); -} From 475bfbf44c91562f8efb6f32355d2e84d3837c5c Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:43:36 -0700 Subject: [PATCH 7/9] Removed persistent_storage.h from args --- .../args/include/args/persistent_storage.h | 95 ------------------- 1 file changed, 95 deletions(-) delete mode 100644 buildcc/lib/args/include/args/persistent_storage.h diff --git a/buildcc/lib/args/include/args/persistent_storage.h b/buildcc/lib/args/include/args/persistent_storage.h deleted file mode 100644 index 573c0172..00000000 --- a/buildcc/lib/args/include/args/persistent_storage.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2021-2022 Niket Naidu. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ARGS_PERSISTENT_STORAGE_H_ -#define ARGS_PERSISTENT_STORAGE_H_ - -#include -#include -#include -#include - -#include "env/assert_fatal.h" - -#include "fmt/format.h" - -namespace buildcc { - -class PersistentStorage { -public: - PersistentStorage() {} - ~PersistentStorage() { - for (const auto &ptr_iter : ptrs_) { - ptr_iter.second.destructor(); - } - ptrs_.clear(); - env::assert_fatal(ptrs_.empty(), "Memory not deallocated"); - } - - template - T &Add(const std::string &identifier, Params &&...params) { - T *ptr = new T(std::forward(params)...); - env::assert_fatal(ptr != nullptr, "System out of memory"); - - PtrMetadata metadata; - metadata.ptr = (void *)ptr; - metadata.typeid_name = typeid(T).name(); - metadata.destructor = [this, identifier, ptr]() { - env::log_trace("Cleaning", identifier); - Remove(ptr); - }; - ptrs_.emplace(identifier, metadata); - return *ptr; - } - - template void Remove(T *ptr) { delete ptr; } - - template const T &ConstRef(const std::string &identifier) const { - const PtrMetadata &metadata = ptrs_.at(identifier); - env::assert_fatal( - typeid(T).name() == metadata.typeid_name, - fmt::format("Wrong type, expects: {}", metadata.typeid_name)); - const T *p = (const T *)metadata.ptr; - return *p; - } - - // https://stackoverflow.com/questions/123758/how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-func/123995 - template T &Ref(const std::string &identifier) { - return const_cast( - static_cast(*this).ConstRef(identifier)); - } - -private: - /** - * @brief - * @param ptr Can hold data of any type - * @param typeid_name We cannot store a template type so this is the next best - * thing - * @param desstructor Destructor callback to delete ptr - */ - struct PtrMetadata { - void *ptr; - std::string typeid_name; - std::function destructor; - }; - -private: - std::unordered_map ptrs_; -}; - -} // namespace buildcc - -#endif From 9d79b1026843df3ede7df8ed7baf9a2b977f23a0 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:43:59 -0700 Subject: [PATCH 8/9] Updated args CMakeLists.txt --- buildcc/lib/args/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/buildcc/lib/args/CMakeLists.txt b/buildcc/lib/args/CMakeLists.txt index c0bdc98b..6535b1f3 100644 --- a/buildcc/lib/args/CMakeLists.txt +++ b/buildcc/lib/args/CMakeLists.txt @@ -56,7 +56,6 @@ set(ARGS_SRCS src/tasks.cpp include/args/args.h include/args/register.h - include/args/persistent_storage.h ) if(${BUILDCC_BUILD_AS_SINGLE_LIB}) From bf3675ae90380b71436baf0902b7f0bc8e453d12 Mon Sep 17 00:00:00 2001 From: Niket Naidu Date: Wed, 20 Apr 2022 21:44:13 -0700 Subject: [PATCH 9/9] Updated build files with ScopedStorage --- bootstrap/include/bootstrap/build_buildcc.h | 2 +- buildexe/include/buildexe/build_env_setup.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bootstrap/include/bootstrap/build_buildcc.h b/bootstrap/include/bootstrap/build_buildcc.h index 7dcb9aee..4f0d59e7 100644 --- a/bootstrap/include/bootstrap/build_buildcc.h +++ b/bootstrap/include/bootstrap/build_buildcc.h @@ -77,7 +77,7 @@ class BuildBuildCC { const BaseToolchain &toolchain_; TargetEnv env_; - PersistentStorage storage_; + ScopedStorage storage_; }; } // namespace buildcc diff --git a/buildexe/include/buildexe/build_env_setup.h b/buildexe/include/buildexe/build_env_setup.h index e36983d4..f76fd9fc 100644 --- a/buildexe/include/buildexe/build_env_setup.h +++ b/buildexe/include/buildexe/build_env_setup.h @@ -66,7 +66,7 @@ class BuildEnvSetup { const BuildExeArgs &buildexe_args_; ArgToolchainState state_; - PersistentStorage storage_; + ScopedStorage storage_; }; } // namespace buildcc