diff --git a/CMakeLists.txt b/CMakeLists.txt index c2b1653..f25643d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ project (libgit2cpp) cmake_minimum_required(VERSION 2.8) +# Build options +OPTION( USE_BOOST "Enable use of boost header libraries" OFF ) + + set(CMAKE_CXX_FLAGS -std=c++11) file(GLOB lib_sources @@ -8,6 +12,12 @@ file(GLOB lib_sources include/git2cpp/*.h ) +IF(USE_BOOST) + add_definitions(-DUSE_BOOST=1) + find_package(Boost REQUIRED) + include_directories(${BOOST_INCLUDEDIR}) +ENDIF() + add_library(git2cpp ${lib_sources}) target_include_directories(git2cpp @@ -41,4 +51,4 @@ foreach (example ${examples}) target_link_libraries(${example} git2cpp) endforeach(example) -file(COPY test.sh DESTINATION . FILE_PERMISSIONS ${EXE_PERM}) \ No newline at end of file +file(COPY test.sh DESTINATION . FILE_PERMISSIONS ${EXE_PERM}) diff --git a/examples/log.cpp b/examples/log.cpp index 76a5084..3b814c3 100644 --- a/examples/log.cpp +++ b/examples/log.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include @@ -16,6 +14,8 @@ #include "git2cpp/revwalker.h" #include "git2cpp/diff.h" +#include "git2cpp/internal/optional.h" + static void usage(const char *message, const char *arg) { if (message && arg) @@ -26,11 +26,11 @@ static void usage(const char *message, const char *arg) exit(1); } -struct log_state +struct log_state { std::string repodir = "."; - boost::optional repo; - boost::optional walker; + git::internal::optional repo; + git::internal::optional walker; int hide = 0; git::revwalker::sorting::type sorting = git::revwalker::sorting::time; }; @@ -38,7 +38,7 @@ struct log_state static void set_sorting(struct log_state *s, git::revwalker::sorting::type sort_mode) { if (!s->repo) { - s->repo = boost::in_place(s->repodir); + git::internal::emplace(s->repo, s->repodir); } if (!s->walker) @@ -91,7 +91,7 @@ void add_revision(struct log_state *s, const char *revstr) int hide = 0; if (!s->repo) { - s->repo = boost::in_place(s->repodir); + git::internal::emplace(s->repo, s->repodir); } if (!revstr) { diff --git a/examples/rev-parse.cpp b/examples/rev-parse.cpp index 257f040..556d230 100644 --- a/examples/rev-parse.cpp +++ b/examples/rev-parse.cpp @@ -3,8 +3,7 @@ #include #include -#include -#include +#include #include "git2cpp/initializer.h" #include "git2cpp/repo.h" @@ -22,14 +21,14 @@ static void usage(const char *message, const char *arg) } struct parse_state { - boost::optional repo; - std::string repodir = "."; + std::shared_ptr repo; + std::string repodir = "."; }; void parse_revision(parse_state & ps, const char *revstr) { - if (!ps.repo) - ps.repo = boost::in_place(ps.repodir); + if (!ps.repo) + ps.repo = std::make_shared(ps.repodir); Revspec rs = ps.repo->revparse(revstr); diff --git a/include/git2cpp/error.h b/include/git2cpp/error.h index 623b3f5..4ecda46 100644 --- a/include/git2cpp/error.h +++ b/include/git2cpp/error.h @@ -2,16 +2,15 @@ #include -#include - #include "id_to_str.h" +#include "internal/format.h" namespace git { + struct error_t : std::runtime_error { explicit error_t(std::string const & message) : std::runtime_error(message) {} - explicit error_t(boost::format const & message) : error_t(str(message)) {} }; struct repository_open_error : error_t @@ -88,7 +87,7 @@ namespace git struct revparse_error : error_t { explicit revparse_error(const char * spec) - : error_t(boost::format("Could not resolve %1%") % spec) + : error_t(internal::format("Could not resolve %s", spec)) {} }; @@ -107,21 +106,21 @@ namespace git struct file_not_found_error : error_t { explicit file_not_found_error(const char * filepath) - : error_t(boost::format("file path \"%1%\" not found") % filepath) + : error_t(internal::format("file path \"%s\" not found", filepath)) {} }; struct ambiguous_path_error : error_t { explicit ambiguous_path_error(const char * filepath) - : error_t(boost::format("file path \"%1%\" is ambiguous") % filepath) + : error_t(internal::format("file path \"%s\" is ambiguous", filepath)) {} }; struct unknown_file_status_error : error_t { explicit unknown_file_status_error(const char * filepath) - : error_t(boost::format("unknown error during getting status for file \"%1%\"") % filepath) + : error_t(internal::format("unknown error during getting status for file \"%s\"", filepath)) {} }; @@ -143,7 +142,7 @@ namespace git struct non_commit_object_error : error_t { explicit non_commit_object_error(git_oid const & id) - : error_t(str(boost::format("object %1% is not a commit") % id_to_str(id))) + : error_t(internal::format("object %s is not a commit", id_to_str(id).c_str())) {} }; @@ -182,11 +181,11 @@ namespace git struct merge_base_error : error_t { - merge_base_error(git_oid const & c1, git_oid const & c2) - : error_t(boost::format("Could not find merge base for commits %1% and % 2%") - % id_to_str(c1, 8) - % id_to_str(c2, 8)) - {} + merge_base_error(git_oid const & c1, git_oid const & c2) + : error_t(internal::format( + "Could not find merge base for commits %s and %s", id_to_str(c1, 8).c_str(), id_to_str(c2, 8).c_str() + )) + {} }; struct config_open_error : error_t diff --git a/include/git2cpp/internal/format.h b/include/git2cpp/internal/format.h new file mode 100644 index 0000000..a49d18f --- /dev/null +++ b/include/git2cpp/internal/format.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#ifdef USE_BOOST +#include +#endif + +namespace git { +namespace internal { + +#ifndef USE_BOOST + template + inline std::string format(const char * fmt, Args&& ... args) + { + auto size = std::snprintf(nullptr, 0, fmt, args...); + std::string result(size, 0); + std::snprintf(&result[0], size + 1, fmt, args...); + return result; + } +#else + inline boost::format & format_apply(boost::format & fmt){ + return fmt; + } + + template + inline boost::format & format_apply(Format && fmt, T && data, Args&& ... args){ + return format_apply(fmt % data, std::forward(args)...); + } + + template + inline std::string format(const char * fmt, Args&& ... args){ + return boost::str(format_apply(boost::format(fmt), std::forward(args)...)); + } +#endif + +}//namespace +}//namespace diff --git a/include/git2cpp/internal/optional.h b/include/git2cpp/internal/optional.h new file mode 100644 index 0000000..e337f75 --- /dev/null +++ b/include/git2cpp/internal/optional.h @@ -0,0 +1,172 @@ +#pragma once + +#ifdef USE_BOOST + #include + #include +#else + #include + #include +#endif + +namespace git +{ + namespace internal{ + +#ifdef USE_BOOST + using boost::optional; + using boost::in_place; + using boost::none_t; + using boost::none; + + template + optional & emplace(optional & opt, Args&&... args){ + opt = in_place(std::forward(args)...); + return opt; + } +#else + typedef nullptr_t none_t; + const constexpr none_t none = nullptr; + + //Simple (and incomplete) optional implementations + template + class optional{ + public: //type alias + typedef typename std::aligned_storage::type + StorageT; + using optionalT = optional; + + public: //type traits + enum non_movable_t{}; + enum non_copyable_t{}; + + static const constexpr bool movable = std::is_move_constructible::value && std::is_move_assignable::value; + static const constexpr bool copyable = std::is_copy_constructible::value && std::is_copy_assignable::value; + typedef typename std::conditional::type MovableT; + typedef typename std::conditional::type CopyableT; + + public: //initializing and attribution + constexpr + optional(none_t t = none){} + optional(const T & v) { assign(v);} + optional(T && v) { assign(std::forward(v));} + + optional(const optionalT & other){ assign(other);} + optional( optionalT && other){ assign(std::move(other));} + + optionalT & operator=(none_t none) { reset(); return *this;} + optionalT & operator=(T && v) { return assign(std::forward(v));} + optionalT & operator=(const T & v) { return assign(v);} + + optionalT & operator=(const optionalT & other){ return assign(other);} + optionalT & operator=( optionalT && other){ return assign(std::move(other));} + + ~optional() { reset(); } + + public: //getting value + T const* get_ptr() const {return reinterpret_cast(&storage);} + T* get_ptr() {return reinterpret_cast(&storage);} + + const + T& value() const {return *get_ptr();} + T& value() {return *get_ptr();} + + const + T& operator*() const {return value();} + T& operator*() {return value();} + + const + T* operator->() const {return get_ptr();} + T* operator->() {return get_ptr();} + + public: //querying state + bool is_initialized() const {return initialized;} + + operator bool() const { return is_initialized();} + + public: //change state + void reset(){ + if(is_initialized()){ + get_ptr()->~T(); + initialized = false; + } + } + + template + void emplace(Args&&... args){ + if(is_initialized()){ + reset(); + } + init(std::forward(args)...); + } + + protected: //assign + + template + optionalT & assign(U&& u) { + static constexpr const bool same_class = std::is_same, T&>::value; + static_assert(!same_class , "Invalid type"); + static_assert(same_class && !copyable, "Type is non copyable"); + static_assert(same_class && !movable , "Type is non movable"); + + return *this; + } //default case + + optionalT & assign(MovableT && value) { + return set_from_value(std::move(value)); + } + optionalT & assign(const CopyableT & value) { + return set_from_value(value); + } + optionalT & assign(const optionalT & other) { + return set_or_reset(other.value(), other.is_initialized()); + } + optionalT & assign(optionalT && other) { + return set_or_reset(std::move(other.value()), other.is_initialized()); + } + + protected: + template + optionalT & set_or_reset(U&& u, bool isValid) { + if(isValid){ + set_from_value(std::forward(u)); + } + else{ + reset(); + } + + return *this; + } + + template + optionalT & set_from_value(U&& u) { + if(is_initialized()){ + reinterpret_cast(storage) = std::forward(u); + } + else{ + init(std::forward(u)); + } + + return *this; + } + + template + void init(Args&& ... args){ + new (&storage) T(std::forward(args)...); + initialized = true; + } + + protected: + StorageT storage; + bool initialized=false; + }; + + template + optional & emplace(optional & opt, Args&&... args){ + opt.emplace(std::forward(args)...); + return opt; + } + +#endif + + }//namespace internal +}//namespace git diff --git a/src/diff.cpp b/src/diff.cpp index e731422..3f9cc08 100644 --- a/src/diff.cpp +++ b/src/diff.cpp @@ -3,8 +3,12 @@ #include +#ifdef USE_BOOST #include #include +#else +#include +#endif namespace git { @@ -20,15 +24,31 @@ namespace git const type include_summary (GIT_DIFF_STATS_INCLUDE_SUMMARY); }} +#ifdef USE_BOOST + template + using map_container = boost::container::flat_map; +#else + struct EnumHash{ + template + std::size_t operator()(T t) const{ + return static_cast(t); + } + }; + + template + using map_container = std::unordered_map; +#endif + git_diff_format_t convert(format f) { - static const boost::container::flat_map converter - = boost::assign::list_of> - ( format::patch, GIT_DIFF_FORMAT_PATCH ) - ( format::patch_header, GIT_DIFF_FORMAT_PATCH_HEADER ) - ( format::raw, GIT_DIFF_FORMAT_RAW ) - ( format::name_only, GIT_DIFF_FORMAT_NAME_ONLY ) - ( format::name_status, GIT_DIFF_FORMAT_NAME_STATUS ) + static const map_container converter + = { + { format::patch, GIT_DIFF_FORMAT_PATCH }, + { format::patch_header, GIT_DIFF_FORMAT_PATCH_HEADER }, + { format::raw, GIT_DIFF_FORMAT_RAW }, + { format::name_only, GIT_DIFF_FORMAT_NAME_ONLY }, + { format::name_status, GIT_DIFF_FORMAT_NAME_STATUS } + } ; return converter.at(f); } diff --git a/src/repo.cpp b/src/repo.cpp index 7a5b7c2..945a11c 100644 --- a/src/repo.cpp +++ b/src/repo.cpp @@ -8,12 +8,13 @@ #include #include -#include -#include +#include #include "git2cpp/repo.h" #include "git2cpp/error.h" +#include "git2cpp/internal/optional.h" + namespace git { namespace @@ -162,13 +163,13 @@ namespace git { case GIT_OK: assert(type == type_); - ref_ = boost::in_place(ref); + internal::emplace(ref_, ref); break; case GIT_ITEROVER: - ref_ = boost::none; + ref_ = internal::none; break; default: - ref_ = boost::none; + ref_ = internal::none; throw std::logic_error("unknown git_branch_next error"); } } @@ -194,7 +195,7 @@ namespace git private: git_branch_t type_; git_branch_iterator * base_; - boost::optional ref_; + internal::optional ref_; }; std::vector Repository::branches(branch_type type) const diff --git a/src/tree.cpp b/src/tree.cpp index 4eee6f0..a7bcacf 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -72,7 +72,7 @@ namespace git case GIT_ENOTFOUND: throw file_not_found_error(path); default: - throw error_t(boost::format("unknown error inside function: 'git_tree_entry_bypath': %1%") % status); + throw error_t(internal::format("unknown error inside function: 'git_tree_entry_bypath': ", status)); } }