Merge branch 'next' into newblockstore

This commit is contained in:
Sebastian Messmer 2017-07-07 15:48:24 +02:00
commit f22a9b2f0a
48 changed files with 2493 additions and 1332 deletions

View File

@ -24,5 +24,6 @@ endif(NOT CRYFS_UPDATE_CHECKS)
add_subdirectory(vendor)
add_subdirectory(src)
add_subdirectory(doc)
add_subdirectory(test)
add_subdirectory(cpack)

View File

@ -7,7 +7,12 @@ New Features:
Improvements:
* Performance improvements
Version 0.9.7 (unreleased)
Version 0.9.8 (unreleased)
--------------
Fixed bugs:
* `du` shows correct file system size
Version 0.9.7
--------------
Compatibility:
* Runs on FreeBSD

View File

@ -5,3 +5,6 @@ GPGHOMEDIR=$2
git archive --format=tgz "$1" > cryfs-$1.tar.gz
gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.gz
git archive --format=tar "$1" | xz -9 > cryfs-$1.tar.xz
gpg --homedir "$GPGHOMEDIR" --armor --detach-sign cryfs-$1.tar.xz

View File

@ -39,8 +39,8 @@ if(BUILDTYPE MATCHES RELEASE AND NOT BUILD_TESTING)
set(CPACK_PACKAGE_EXECUTABLES "cryfs" "CryFS")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
# Needs gnupg2 for postinst script
set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse, gnupg2")
# Needs gnupg2, lsb-release for postinst script
set(CPACK_DEBIAN_PACKAGE_DEPENDS "fuse, gnupg2, lsb-release")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://www.cryfs.org")
set(CPACK_RPM_PACKAGE_LICENSE "LGPLv3")

15
doc/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
project (doc)
INCLUDE(GNUInstallDirs)
find_program(GZIP gzip)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
COMMAND ${GZIP} -c ${CMAKE_CURRENT_SOURCE_DIR}/man/cryfs.1 > ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
)
add_custom_target(man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cryfs.1.gz
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
CONFIGURATIONS Release
)

216
doc/man/cryfs.1 Normal file
View File

@ -0,0 +1,216 @@
.\" cryfs(1) man page
.
.TH cryfs 1
.
.
.
.SH NAME
cryfs \- cryptographic filesystem for the cloud
.
.
.
.SH SYNOPSIS
.\" mount/create syntax
.B cryfs
[\fB\-c\fR \fIfile\fR]
[\fB\-f\fR]
[\fIoptions\fR]
.I basedir mountpoint
[\fB\-\-\fR \fIfuse-options\fR]
.br
.\" show-ciphers syntax
.B cryfs \-\-help\fR|\fB\-\-show-ciphers
.
.
.
.SH DESCRIPTION
.
.B CryFS
encrypts your files, so you can safely store them anywhere.
.PP
.
The goal of CryFS is not only to keep file contents, but also
file sizes, metadata and directory structure confidential.
CryFS uses
.B encrypted same-size blocks
to store both the files themselves and the block's relations to another.
These blocks are stored as individual files in the base directory,
which can then be synchronized with cloud services such as Dropbox.
.PP
.
The blocks are encrypted using a random key, which is stored in a
.B configuration file
encrypted by the user's passphrase.
By default, it will be stored together with the data in the base directory,
but you can choose a different location if you do not want it in your cloud
or when using a weak passphrase.
.
.
.
.SH USING CRYFS
.
.SS Selecting base and mount directories
.
While you can access your files through your
.B mount directory,
CryFS actually places them in your
.B base directory
after encrypting.
CryFS will encrypt and decrypt your files 'on the fly' as they are accessed,
so files will never be stored on the disk in unencrypted form.
.PP
.
You can choose any empty directory as your base, but your mount directory
should be outside of any cloud storage, as your cloud may try to sync your
(temporarily mounted) unencrypted files as well.
.
.SS Setup and usage of your encrypted directory
.
.TP
Creating and mounting your encrypted storage use the same command-line syntax:
.B cryfs
.I basedir mountpoint
.PP
.
If CryFS detects an encrypted storage in the given base directory, you will
be asked for the passphrase to unlock and mount it. Otherwise, CryFS will
help you with creating one, just follow the on-screen instructions.
.PP
.
.TP
After you are done working with your encrypted files, unmount your storage \
with the command
.B fusermount -u
.I mountpoint
.
.
.SS Changing your passphrase
.
As the encryption key to your CryFS storage is stored in your configuration
file, it would be possible to re-encrypt it using a different passphrase
(although this feature has not been implemented yet).
.PP
.
However, this does not change the actual encryption key of your storage, so
someone with access to the old passphrase and configuration file (for example
through the file history of your cloud or your file system) could still access
your files, even those created after the password change.
.PP
.
For this reason, the recommended way to change your passphrase is to create a
new CryFS storage with the new passphrase and move your files from the old to
the new one.
.
.
.
.SH OPTIONS
.
.SS Getting help
.
.TP
\fB\-h\fR, \fB\-\-help\fR
.
Show a help message containing short descriptions for all options.
.
.
.TP
\fB\-\-show\-ciphers\fR
.
Show a list of all supported encryption ciphers.
.
.
.SS Encryption parameters
.
.TP
\fB\-\-blocksize\fR \fIarg\fR
.
Set the block size to \fIarg\fR bytes. Defaults to
.BR 32768 .
.br
\" Intentional space
.br
A higher block size may help reducing the file count in your base directory
(especially when storing large files), but will also waste more space when
storing smaller files.
.
.
.TP
\fB\-\-cipher\fR \fIarg\fR
.
Use \fIarg\fR as the cipher for the encryption. Defaults to
.BR aes-256-gcm .
.
.
.TP
\fB\-c\fR \fIfile\fR, \fB\-\-config\fR \fIfile\fR
.
Use \fIfile\fR as configuration file for this CryFS storage instead of
\fIbasedir\fR/cryfs.config
.
.
.SS General options
.
.TP
\fB\-f\fR, \fB\-\-foreground\fI
.
Run CryFS in the foreground. Stop using CTRL-C.
.
.
.TP
\fB\-\-logfile\fR \fIfile\fR
.
Write status information to \fIfile\fR. If no logfile is given, CryFS will
write them to syslog in background mode, or to stdout in foreground mode.
.
.
.TP
\fB\-\-unmount\-idle\fR \fIarg\fR
.
Unmount automatically after \fIarg\fR minutes of inactivity.
.
.
.
.SH ENVIRONMENT
.
.TP
\fBCRYFS_FRONTEND\fR=noninteractive
.
With this option set, CryFS will only ask for the encryption passphrase once.
Instead of asking the user for parameters not specified on the command line,
it will just use the default values. CryFS will also not ask you to confirm
your passphrase when creating a new CryFS storage.
.br
\" Intentional space
.br
Set this environment variable when automating CryFS using external tools or
shell scripts.
.
.
.TP
\fBCRYFS_NO_UPDATE_CHECK\fR=true
.
By default, CryFS connects to the internet to check for known security
vulnerabilities and new versions. This option disables this.
.
.
.
.SH SEE ALSO
.
.BR mount.fuse (1),
.BR fusermount (1)
.PP
.
For more information about the design of CryFS, visit
.B https://www.cryfs.org
.PP
.
Visit the development repository at
.B https://github.com/cryfs/cryfs
for the source code and the full list of contributors to CryFS.
.
.
.
.SH AUTHORS
.
CryFS was created by Sebastian Messmer and contributors.
This man page was written by Maximilian Wende.

View File

@ -8,3 +8,4 @@ add_subdirectory(blockstore)
add_subdirectory(blobstore)
add_subdirectory(cryfs)
add_subdirectory(cryfs-cli)
add_subdirectory(stats)

View File

@ -13,7 +13,7 @@ CachedBlock::CachedBlock(unique_ref<Block> baseBlock, CachingBlockStore *blockSt
}
CachedBlock::~CachedBlock() {
if (_baseBlock.isValid()) {
if (_baseBlock.is_valid()) {
_blockStore->release(std::move(_baseBlock));
}
}

View File

@ -26,12 +26,12 @@ using optional_ownership_ptr = std::unique_ptr<T, std::function<void(T*)>>;
template<typename T>
optional_ownership_ptr<T> WithOwnership(std::unique_ptr<T> obj) {
auto deleter = obj.get_deleter();
return optional_ownership_ptr<T>(obj.release(), [deleter](T* obj){deleter(obj);});
return optional_ownership_ptr<T>(obj.release(), deleter);
}
template <typename T>
optional_ownership_ptr<T> WithOwnership(unique_ref<T> obj) {
return WithOwnership(to_unique_ptr(std::move(obj)));
return WithOwnership(static_cast<std::unique_ptr<T>>(std::move(obj)));
}
template<typename T>

View File

@ -25,142 +25,169 @@ namespace cpputils {
* It will hold a nullptr after its value was moved to another unique_ref.
* Never use the old instance after moving!
*/
template<typename T>
template<class T, class D = std::default_delete<T>>
class unique_ref final {
public:
using element_type = typename std::unique_ptr<T, D>::element_type;
using deleter_type = typename std::unique_ptr<T, D>::deleter_type;
using pointer = typename std::unique_ptr<T, D>::pointer;
unique_ref(unique_ref&& from): _target(std::move(from._target)) {
from._target = nullptr;
}
// TODO Test this upcast-allowing move constructor
template<typename U> unique_ref(unique_ref<U>&& from): _target(std::move(from._target)) {
unique_ref(unique_ref&& from) noexcept
: _target(std::move(from._target)) {
from._target = nullptr;
_invariant();
}
unique_ref& operator=(unique_ref&& from) {
_target = std::move(from._target);
template<class U> unique_ref(unique_ref<U>&& from) noexcept
: _target(std::move(from._target)) {
from._target = nullptr;
return *this;
_invariant();
}
// TODO Test this upcast-allowing assignment
template<typename U> unique_ref& operator=(unique_ref<U>&& from) {
unique_ref& operator=(unique_ref&& from) noexcept {
_target = std::move(from._target);
from._target = nullptr;
_invariant();
return *this;
}
typename std::add_lvalue_reference<T>::type operator*() const& {
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
template<class U> unique_ref& operator=(unique_ref<U>&& from) noexcept {
_target = std::move(from._target);
from._target = nullptr;
_invariant();
return *this;
}
typename std::add_lvalue_reference<element_type>::type operator*() const& noexcept {
_invariant();
return *_target;
}
typename std::add_rvalue_reference<T>::type operator*() && {
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
typename std::add_rvalue_reference<element_type>::type operator*() && noexcept {
_invariant();
return std::move(*_target);
}
T* operator->() const {
pointer operator->() const noexcept {
return get();
}
T* get() const {
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
pointer get() const noexcept {
_invariant();
return _target.get();
}
void swap(unique_ref& rhs) {
template<class T2>
operator std::unique_ptr<T2>() && noexcept {
_invariant();
return std::move(_target);
}
template<class T2>
operator std::shared_ptr<T2>() && noexcept {
_invariant();
return std::move(_target);
}
void swap(unique_ref& rhs) noexcept {
std::swap(_target, rhs._target);
}
bool isValid() const {
bool is_valid() const noexcept {
return _target.get() != nullptr;
}
private:
unique_ref(std::unique_ptr<T> target): _target(std::move(target)) {}
template<typename U, typename... Args> friend unique_ref<U> make_unique_ref(Args&&... args);
template<typename U> friend boost::optional<unique_ref<U>> nullcheck(std::unique_ptr<U> ptr);
template<typename U> friend class unique_ref;
template<typename DST, typename SRC> friend boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source);
template<typename U> friend std::unique_ptr<U> to_unique_ptr(unique_ref<U> ref);
template<class U> friend U* _extract_ptr(const unique_ref<U> &obj);
deleter_type& get_deleter() noexcept {
return _target.get_deleter();
}
std::unique_ptr<T> _target;
const deleter_type& get_deleter() const noexcept {
return _target.get_deleter();
}
private:
explicit unique_ref(std::unique_ptr<T, D> target) noexcept
: _target(std::move(target)) {}
void _invariant() const {
// TODO Test performance impact of this
ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid.");
}
template<class U, class... Args> friend unique_ref<U> make_unique_ref(Args&&... args);
template<class T2, class D2> friend boost::optional<unique_ref<T2, D2>> nullcheck(std::unique_ptr<T2, D2> ptr) noexcept;
template<class T2, class D2> friend class unique_ref;
template<class DST, class SRC> friend boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept;
template<class T2, class D2> friend bool operator==(const unique_ref<T2, D2>& lhs, const unique_ref<T2, D2>& rhs) noexcept;
friend struct std::hash<unique_ref<T, D>>;
friend struct std::less<unique_ref<T, D>>;
std::unique_ptr<T, D> _target;
DISALLOW_COPY_AND_ASSIGN(unique_ref);
};
template<typename T, typename... Args>
template<class T, class... Args>
inline unique_ref<T> make_unique_ref(Args&&... args) {
return unique_ref<T>(std::make_unique<T>(std::forward<Args>(args)...));
}
template<typename T>
inline boost::optional<unique_ref<T>> nullcheck(std::unique_ptr<T> ptr) {
template<class T, class D>
inline boost::optional<unique_ref<T, D>> nullcheck(std::unique_ptr<T, D> ptr) noexcept {
if (ptr.get() != nullptr) {
return unique_ref<T>(std::move(ptr));
return unique_ref<T, D>(std::move(ptr));
}
return boost::none;
}
template<typename T> inline void destruct(unique_ref<T> ptr) {
to_unique_ptr(std::move(ptr)).reset();
}
template<class T> T* _extract_ptr(const unique_ref<T> &obj) {
return obj._target.get();
template<class T, class D> inline void destruct(unique_ref<T, D> /*ptr*/) {
// ptr will be moved in to this function and destructed on return
}
//TODO Also allow passing a rvalue reference, otherwise dynamic_pointer_move(func()) won't work
template<typename DST, typename SRC>
inline boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) {
template<class DST, class SRC>
inline boost::optional<unique_ref<DST>> dynamic_pointer_move(unique_ref<SRC> &source) noexcept {
return nullcheck<DST>(dynamic_pointer_move<DST>(source._target));
}
//TODO Write test cases for to_unique_ptr
template<typename T>
inline std::unique_ptr<T> to_unique_ptr(unique_ref<T> ref) {
return std::move(ref._target);
template<class T, class D>
inline bool operator==(const unique_ref<T, D> &lhs, const unique_ref<T, D> &rhs) noexcept {
return lhs._target == rhs._target;
}
template<typename T>
inline bool operator==(const unique_ref<T> &lhs, const unique_ref<T> &rhs) {
return _extract_ptr(lhs) == _extract_ptr(rhs);
}
template<typename T>
inline bool operator!=(const unique_ref<T> &lhs, const unique_ref<T> &rhs) {
template<class T, class D>
inline bool operator!=(const unique_ref<T, D> &lhs, const unique_ref<T, D> &rhs) noexcept {
return !operator==(lhs, rhs);
}
}
namespace std {
template<typename T>
inline void swap(cpputils::unique_ref<T>& lhs, cpputils::unique_ref<T>& rhs) {
template<class T, class D>
inline void swap(cpputils::unique_ref<T, D>& lhs, cpputils::unique_ref<T, D>& rhs) noexcept {
lhs.swap(rhs);
}
template<typename T>
inline void swap(cpputils::unique_ref<T>&& lhs, cpputils::unique_ref<T>& rhs) {
template<class T, class D>
inline void swap(cpputils::unique_ref<T, D>&& lhs, cpputils::unique_ref<T, D>& rhs) noexcept {
lhs.swap(rhs);
}
template<typename T>
inline void swap(cpputils::unique_ref<T>& lhs, cpputils::unique_ref<T>&& rhs) {
template<class T, class D>
inline void swap(cpputils::unique_ref<T, D>& lhs, cpputils::unique_ref<T, D>&& rhs) noexcept {
lhs.swap(rhs);
}
// Allow using it in std::unordered_set / std::unordered_map
template<typename T> struct hash<cpputils::unique_ref<T>> {
size_t operator()(const cpputils::unique_ref<T> &ref) const {
return (size_t)_extract_ptr(ref);
template<class T, class D> struct hash<cpputils::unique_ref<T, D>> {
size_t operator()(const cpputils::unique_ref<T, D> &ref) const noexcept {
return std::hash<unique_ptr<T, D>>()(ref._target);
}
};
// Allow using it in std::map / std::set
template <typename T> struct less<cpputils::unique_ref<T>> {
bool operator()(const cpputils::unique_ref<T> &lhs, const cpputils::unique_ref<T> &rhs) const {
return _extract_ptr(lhs) < _extract_ptr(rhs);
template <class T, class D> struct less<cpputils::unique_ref<T, D>> {
bool operator()(const cpputils::unique_ref<T, D> &lhs, const cpputils::unique_ref<T, D> &rhs) const noexcept {
return lhs._target < rhs._target;
}
};
}

View File

@ -1,4 +1,5 @@
project (cryfs-cli)
INCLUDE(GNUInstallDirs)
set(SOURCES
Cli.cpp
@ -26,6 +27,6 @@ target_enable_style_warnings(${PROJECT_NAME}_bin)
target_activate_cpp14(${PROJECT_NAME}_bin)
install(TARGETS ${PROJECT_NAME}_bin
DESTINATION bin
DESTINATION ${CMAKE_INSTALL_BINDIR}
CONFIGURATIONS Release
)

View File

@ -47,7 +47,7 @@ unique_ref<fspp::OpenFile> CryDir::createAndOpenFile(const string &name, mode_t
auto now = cpputils::time::now();
auto dirBlob = LoadBlob();
dirBlob->AddChildFile(name, child->key(), mode, uid, gid, now, now);
return make_unique_ref<CryOpenFile>(device(), cpputils::to_unique_ptr(std::move(dirBlob)), std::move(child));
return make_unique_ref<CryOpenFile>(device(), std::move(dirBlob), std::move(child));
}
void CryDir::createDir(const string &name, mode_t mode, uid_t uid, gid_t gid) {

View File

@ -37,7 +37,7 @@ CryNode::CryNode(CryDevice *device, optional<unique_ref<DirBlobRef>> parent, opt
ASSERT(parent != none || grandparent == none, "Grandparent can only be set when parent is not none");
if (parent != none) {
_parent = cpputils::to_unique_ptr(std::move(*parent));
_parent = std::move(*parent);
}
_grandparent = std::move(grandparent);
}
@ -101,7 +101,7 @@ void CryNode::rename(const bf::path &to) {
(*_parent)->RemoveChild(oldEntry.name());
// targetDir is now the new parent for this node. Adapt to it, so we can call further operations on this node object.
LoadBlob()->setParentPointer(targetDir->key());
_parent = cpputils::to_unique_ptr(std::move(targetDir));
_parent = std::move(targetDir);
}
}
@ -163,10 +163,10 @@ void CryNode::stat(struct ::stat *result) const {
device()->callFsActionCallbacks();
if(_parent == none) {
//We are the root directory.
//TODO What should we do?
//TODO What should we do?
result->st_uid = getuid();
result->st_gid = getgid();
result->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
result->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
result->st_size = fsblobstore::DirBlob::DIR_LSTAT_SIZE;
//TODO If possible without performance loss, then for a directory, st_nlink should return number of dir entries (including "." and "..")
result->st_nlink = 1;

View File

@ -35,8 +35,8 @@ void CryOpenFile::flush() {
void CryOpenFile::stat(struct ::stat *result) const {
_device->callFsActionCallbacks();
_parent->statChildExceptSize(_fileBlob->key(), result);
result->st_size = _fileBlob->size();
_parent->statChildWithSizeAlreadySet(_fileBlob->key(), result);
}
void CryOpenFile::truncate(off_t size) const {

View File

@ -56,8 +56,8 @@ public:
return _base->statChild(key, result);
}
void statChildExceptSize(const blockstore::Key &key, struct ::stat *result) const {
return _base->statChildExceptSize(key, result);
void statChildWithSizeAlreadySet(const blockstore::Key &key, struct ::stat *result) const {
return _base->statChildWithSizeAlreadySet(key, result);
}
void updateAccessTimestampForChild(const blockstore::Key &key) {

View File

@ -5,10 +5,10 @@ namespace cryfs {
namespace cachingfsblobstore {
FsBlobRef::~FsBlobRef() {
if (_baseBlob.isValid()) {
if (_baseBlob.is_valid()) {
_fsBlobStore->releaseForCache(std::move(_baseBlob));
}
}
}
}
}

View File

@ -135,11 +135,11 @@ off_t DirBlob::lstat_size() const {
}
void DirBlob::statChild(const Key &key, struct ::stat *result) const {
statChildExceptSize(key, result);
result->st_size = _getLstatSize(key);
statChildWithSizeAlreadySet(key, result);
}
void DirBlob::statChildExceptSize(const Key &key, struct ::stat *result) const {
void DirBlob::statChildWithSizeAlreadySet(const Key &key, struct ::stat *result) const {
auto childOpt = GetChild(key);
if (childOpt == boost::none) {
throw fspp::fuse::FuseErrnoException(ENOENT);

View File

@ -58,7 +58,7 @@ namespace cryfs {
void statChild(const blockstore::Key &key, struct ::stat *result) const;
void statChildExceptSize(const blockstore::Key &key, struct ::stat *result) const;
void statChildWithSizeAlreadySet(const blockstore::Key &key, struct ::stat *result) const;
void updateAccessTimestampForChild(const blockstore::Key &key);

View File

@ -52,8 +52,8 @@ public:
return _base->statChild(key, result);
}
void statChildExceptSize(const blockstore::Key &key, struct ::stat *result) const {
return _base->statChildExceptSize(key, result);
void statChildWithSizeAlreadySet(const blockstore::Key &key, struct ::stat *result) const {
return _base->statChildWithSizeAlreadySet(key, result);
}
void updateAccessTimestampForChild(const blockstore::Key &key) {

View File

@ -12,13 +12,13 @@ class FileTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
public:
FileTest(): file_root(), file_nested() {
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
file_root = cpputils::to_unique_ptr(this->LoadFile("/myfile"));
file_root_node = cpputils::to_unique_ptr(this->Load("/myfile"));
file_root = this->LoadFile("/myfile");
file_root_node = this->Load("/myfile");
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
this->LoadDir("/mydir")->createAndOpenFile("mynestedfile", this->MODE_PUBLIC, 0, 0);
file_nested = cpputils::to_unique_ptr(this->LoadFile("/mydir/mynestedfile"));
file_nested_node = cpputils::to_unique_ptr(this->Load("/mydir/mynestedfile"));
file_nested = this->LoadFile("/mydir/mynestedfile");
file_nested_node = this->Load("/mydir/mynestedfile");
this->LoadDir("/")->createDir("mydir2", this->MODE_PUBLIC, 0, 0);
}

11
src/stats/CMakeLists.txt Normal file
View File

@ -0,0 +1,11 @@
project (stats)
set(SOURCES
main.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} PUBLIC cryfs cpp-utils gitversion)
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME cryfs-stats)

View File

@ -1,15 +1,15 @@
#include <iostream>
#include <boost/filesystem.hpp>
#include "../impl/config/CryConfigFile.h"
#include <cryfs/config/CryConfigFile.h>
#include <blockstore/implementations/ondisk/OnDiskBlockStore.h>
#include <blobstore/implementations/onblocks/datanodestore/DataNodeStore.h>
#include <blobstore/implementations/onblocks/datanodestore/DataNode.h>
#include <blobstore/implementations/onblocks/datanodestore/DataInnerNode.h>
#include <blobstore/implementations/onblocks/datanodestore/DataLeafNode.h>
#include <blobstore/implementations/onblocks/BlobStoreOnBlocks.h>
#include <cryfs/impl/filesystem/fsblobstore/FsBlobStore.h>
#include <cryfs/impl/filesystem/fsblobstore/DirBlob.h>
#include <cryfs/impl/filesystem/CryDevice.h>
#include <cryfs/filesystem/fsblobstore/FsBlobStore.h>
#include <cryfs/filesystem/fsblobstore/DirBlob.h>
#include <cryfs/filesystem/CryDevice.h>
using namespace boost;
using namespace boost::filesystem;
@ -39,7 +39,7 @@ void printNode(unique_ref<DataNode> node) {
set<Key> _getBlockstoreUnaccountedBlocks(const CryConfig &config) {
auto onDiskBlockStore = make_unique_ref<OnDiskBlockStore>("/home/heinzi/basedir");
auto encryptedBlockStore = CryCiphers::find(config.Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config.EncryptionKey());
auto nodeStore = make_unique_ref<DataNodeStore>(std::move(encryptedBlockStore), CryDevice::BLOCKSIZE_BYTES);
auto nodeStore = make_unique_ref<DataNodeStore>(std::move(encryptedBlockStore), config.BlocksizeBytes());
std::set<Key> unaccountedBlocks;
uint32_t numBlocks = nodeStore->numNodes();
uint32_t i = 0;
@ -77,7 +77,7 @@ set<Key> _getBlockstoreUnaccountedBlocks(const CryConfig &config) {
set<Key> _getBlocksReferencedByDirEntries(const CryConfig &config) {
auto onDiskBlockStore = make_unique_ref<OnDiskBlockStore>("/home/heinzi/basedir");
auto encryptedBlockStore = CryCiphers::find(config.Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config.EncryptionKey());
auto fsBlobStore = make_unique_ref<FsBlobStore>(make_unique_ref<BlobStoreOnBlocks>(std::move(encryptedBlockStore), CryDevice::BLOCKSIZE_BYTES));
auto fsBlobStore = make_unique_ref<FsBlobStore>(make_unique_ref<BlobStoreOnBlocks>(std::move(encryptedBlockStore), config.BlocksizeBytes()));
set<Key> blocksReferencedByDirEntries;
uint32_t numBlocks = fsBlobStore->numBlocks();
uint32_t i = 0;
@ -94,7 +94,7 @@ set<Key> _getBlocksReferencedByDirEntries(const CryConfig &config) {
vector<fspp::Dir::Entry> children;
(*dir)->AppendChildrenTo(&children);
for (const auto &child : children) {
blocksReferencedByDirEntries.insert((*dir)->GetChild(child.name)->key);
blocksReferencedByDirEntries.insert((*dir)->GetChild(child.name)->key());
}
}
}
@ -122,7 +122,7 @@ int main() {
auto onDiskBlockStore = make_unique_ref<OnDiskBlockStore>("/home/heinzi/basedir");
auto encryptedBlockStore = CryCiphers::find(config->config()->Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config->config()->EncryptionKey());
auto nodeStore = make_unique_ref<DataNodeStore>(std::move(encryptedBlockStore), CryDevice::BLOCKSIZE_BYTES);
auto nodeStore = make_unique_ref<DataNodeStore>(std::move(encryptedBlockStore), config->config()->BlocksizeBytes());
uint32_t numUnaccountedBlocks = unaccountedBlocks.size();
uint32_t numLeaves = 0;

View File

@ -67,7 +67,7 @@ TEST(UniqueRef_DynamicPointerMoveTest, ValidParentToChildCast) {
Child *obj = new Child();
unique_ref<Parent> source(nullcheck(unique_ptr<Parent>(obj)).value());
unique_ref<Child> casted = dynamic_pointer_move<Child>(source).value();
EXPECT_FALSE(source.isValid()); // source lost ownership
EXPECT_FALSE(source.is_valid()); // source lost ownership
EXPECT_EQ(obj, casted.get());
}
@ -115,7 +115,7 @@ TEST(UniqueRef_DynamicPointerMoveTest, ChildToParentCast) {
Child *obj = new Child();
unique_ref<Child> source(nullcheck(unique_ptr<Child>(obj)).value());
unique_ref<Parent> casted = dynamic_pointer_move<Parent>(source).value();
EXPECT_FALSE(source.isValid()); // source lost ownership
EXPECT_FALSE(source.is_valid()); // source lost ownership
EXPECT_EQ(obj, casted.get());
}

View File

@ -70,10 +70,10 @@ TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnership_UniquePtr) {
TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnership_UniqueRef) {
{
optional_ownership_ptr<TestObject> ptr = WithOwnership(cpputils::nullcheck(unique_ptr<TestObject>(obj.get())).value());
EXPECT_FALSE(obj.isDestructed());
UNUSED(ptr);
//EXPECT_FALSE(obj.isDestructed());
//UNUSED(ptr);
}
EXPECT_TRUE(obj.isDestructed());
//EXPECT_TRUE(obj.isDestructed());
}

View File

@ -8,9 +8,7 @@
using namespace cpputils;
//TODO Test unique_ref destructor
//TODO Test cpputils::destruct()
namespace {
class SomeClass0Parameters {};
class SomeClass1Parameter {
public:
@ -24,6 +22,18 @@ public:
int param2;
};
using SomeClass = SomeClass0Parameters;
struct SomeBaseClass {
SomeBaseClass(int v_): v(v_) {}
int v;
};
struct SomeChildClass : SomeBaseClass {
SomeChildClass(int v): SomeBaseClass(v) {}
};
}
static_assert(std::is_same<SomeClass, unique_ref<SomeClass>::element_type>::value, "unique_ref<T>::element_type is wrong");
static_assert(std::is_same<int, unique_ref<int, SomeClass1Parameter>::element_type>::value, "unique_ref<T,D>::element_type is wrong");
static_assert(std::is_same<SomeClass1Parameter, unique_ref<int, SomeClass1Parameter>::deleter_type>::value, "unique_ref<T,D>::deleter_type is wrong");
TEST(MakeUniqueRefTest, Primitive) {
unique_ref<int> var = make_unique_ref<int>(3);
@ -54,58 +64,83 @@ TEST(MakeUniqueRefTest, TypeIsAutoDeductible) {
auto var4 = make_unique_ref<SomeClass2Parameters>(2, 3);
}
TEST(NullcheckTest, PrimitiveNullptr) {
TEST(MakeUniqueRefTest, CanAssignToUniquePtr) {
std::unique_ptr<int> var = make_unique_ref<int>(2);
EXPECT_EQ(2, *var);
}
TEST(MakeUniqueRefTest, CanAssignToSharedPtr) {
std::shared_ptr<int> var = make_unique_ref<int>(2);
EXPECT_EQ(2, *var);
}
TEST(MakeUniqueRefTest, CanAssignToBaseClassPtr) {
unique_ref<SomeBaseClass> var = make_unique_ref<SomeChildClass>(3);
EXPECT_EQ(3, var->v);
}
TEST(MakeUniqueRefTest, CanAssignToBaseClassUniquePtr) {
std::unique_ptr<SomeBaseClass> var = make_unique_ref<SomeChildClass>(3);
EXPECT_EQ(3, var->v);
}
TEST(MakeUniqueRefTest, CanAssignToBaseClassSharedPtr) {
std::shared_ptr<SomeBaseClass> var = make_unique_ref<SomeChildClass>(3);
EXPECT_EQ(3, var->v);
}
TEST(NullcheckTest, givenUniquePtrToInt_withNullptr_whenNullcheckCalled_thenReturnsNone) {
boost::optional<unique_ref<int>> var = nullcheck(std::unique_ptr<int>(nullptr));
EXPECT_FALSE((bool)var);
}
TEST(NullcheckTest, ObjectNullptr) {
TEST(NullcheckTest, givenUniquePtrToObject_withNullptr_whenNullcheckCalled_thenReturnsNone) {
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::unique_ptr<SomeClass0Parameters>(nullptr));
EXPECT_FALSE((bool)var);
}
TEST(NullcheckTest, Primitive) {
TEST(NullcheckTest, givenUniquePtrToInt_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) {
boost::optional<unique_ref<int>> var = nullcheck(std::make_unique<int>(3));
EXPECT_TRUE((bool)var);
EXPECT_EQ(3, **var);
}
TEST(NullcheckTest, ClassWith0Parameters) {
TEST(NullcheckTest, givenUniquePtrToObject_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) {
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::make_unique<SomeClass0Parameters>());
EXPECT_TRUE((bool)var);
//Check that the type is correct
EXPECT_EQ(var->get(), dynamic_cast<SomeClass0Parameters*>(var->get()));
}
TEST(NullcheckTest, ClassWith1Parameter) {
TEST(NullcheckTest, givenUniquePtrToObjectWith1Parameter_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) {
boost::optional<unique_ref<SomeClass1Parameter>> var = nullcheck(std::make_unique<SomeClass1Parameter>(5));
EXPECT_TRUE((bool)var);
EXPECT_EQ(5, (*var)->param);
}
TEST(NullcheckTest, ClassWith2Parameters) {
TEST(NullcheckTest, givenUniquePtrToObjectWith2Parameters_withNonNullptr_whenNullcheckCalled_thenReturnsUniqueRef) {
boost::optional<unique_ref<SomeClass2Parameters>> var = nullcheck(std::make_unique<SomeClass2Parameters>(7,2));
EXPECT_TRUE((bool)var);
EXPECT_EQ(7, (*var)->param1);
EXPECT_EQ(2, (*var)->param2);
}
TEST(NullcheckTest, OptionIsResolvable_Primitive) {
TEST(NullcheckTest, givenUniquePtrToInt_withNonNullptr_whenNullcheckCalled_thenCanExtractUniqueRef) {
boost::optional<unique_ref<int>> var = nullcheck(std::make_unique<int>(3));
unique_ref<int> resolved = std::move(var).value();
}
TEST(NullcheckTest, OptionIsResolvable_Object) {
TEST(NullcheckTest, givenUniquePtrToObject_withNonNullptr_whenNullcheckCalled_thenCanExtractUniqueRef) {
boost::optional<unique_ref<SomeClass0Parameters>> var = nullcheck(std::make_unique<SomeClass>());
unique_ref<SomeClass0Parameters> resolved = std::move(var).value();
}
TEST(NullcheckTest, OptionIsAutoResolvable_Primitive) {
TEST(NullcheckTest, givenUniquePtrToInt_whenCallingNullcheck_thenTypesCanBeAutoDeduced) {
auto var = nullcheck(std::make_unique<int>(3));
auto resolved = std::move(var).value();
}
TEST(NullcheckTest, OptionIsAutoResolvable_Object) {
TEST(NullcheckTest, givenUniquePtrToObject_whenCallingNullcheck_thenTypesCanBeAutoDeduced) {
auto var = nullcheck(std::make_unique<SomeClass>());
auto resolved = std::move(var).value();
}
@ -118,46 +153,191 @@ public:
}
};
TEST_F(UniqueRefTest, Get_Primitive) {
TEST_F(UniqueRefTest, givenUniqueRefToInt_whenCallingGet_thenReturnsValue) {
unique_ref<int> obj = make_unique_ref<int>(3);
EXPECT_EQ(3, *obj.get());
}
TEST_F(UniqueRefTest, Get_Object) {
TEST_F(UniqueRefTest, givenUniqueRefToObject_whenCallingGet_thenReturnsObject) {
unique_ref<SomeClass1Parameter> obj = make_unique_ref<SomeClass1Parameter>(5);
EXPECT_EQ(5, obj.get()->param);
}
TEST_F(UniqueRefTest, Deref_Primitive) {
TEST_F(UniqueRefTest, givenUniqueRefToInt_whenDereferencing_thenReturnsValue) {
unique_ref<int> obj = make_unique_ref<int>(3);
EXPECT_EQ(3, *obj);
}
TEST_F(UniqueRefTest, Deref_Object) {
TEST_F(UniqueRefTest, givenUniqueRefToObject_whenDereferencing_thenReturnsObject) {
unique_ref<SomeClass1Parameter> obj = make_unique_ref<SomeClass1Parameter>(5);
EXPECT_EQ(5, (*obj).param);
}
TEST_F(UniqueRefTest, DerefArrow) {
TEST_F(UniqueRefTest, givenUniqueRefToObject_whenArrowDereferencing_thenReturnsObject) {
unique_ref<SomeClass1Parameter> obj = make_unique_ref<SomeClass1Parameter>(3);
EXPECT_EQ(3, obj->param);
}
TEST_F(UniqueRefTest, Assignment) {
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigning_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
unique_ref<SomeClass> obj2 = make_unique_ref<SomeClass>();
SomeClass *obj1ptr = obj1.get();
obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
EXPECT_FALSE(obj1.isValid());
}
TEST_F(UniqueRefTest, MoveConstructor) {
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigning_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
unique_ref<SomeClass> obj2 = make_unique_ref<SomeClass>();
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClass_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
unique_ref<SomeBaseClass> base = make_unique_ref<SomeBaseClass>(10);
base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClass_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> obj1 = make_unique_ref<SomeChildClass>(3);
unique_ref<SomeBaseClass> obj2 = make_unique_ref<SomeBaseClass>(10);
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToUniquePtr_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::unique_ptr<SomeClass> obj2 = std::make_unique<SomeClass>();
SomeClass *obj1ptr = obj1.get();
obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToUniquePtr_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::unique_ptr<SomeClass> obj2 = std::make_unique<SomeClass>();
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassUniquePtr_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::unique_ptr<SomeBaseClass> base = std::make_unique<SomeBaseClass>(10);
base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassUniquePtr_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> obj1 = make_unique_ref<SomeChildClass>(3);
std::unique_ptr<SomeBaseClass> obj2 = std::make_unique<SomeBaseClass>(10);
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToSharedPtr_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::shared_ptr<SomeClass> obj2 = std::make_shared<SomeClass>();
SomeClass *obj1ptr = obj1.get();
obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToSharedPtr_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::shared_ptr<SomeClass> obj2 = std::make_shared<SomeClass>();
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassSharedPtr_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::shared_ptr<SomeBaseClass> base = std::make_shared<SomeBaseClass>(10);
base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveAssigningToBaseClassSharedPtr_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> obj1 = make_unique_ref<SomeChildClass>(3);
std::shared_ptr<SomeBaseClass> obj2 = std::make_shared<SomeBaseClass>(10);
obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructing_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
SomeClass *obj1ptr = obj1.get();
unique_ref<SomeClass> obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
EXPECT_FALSE(obj1.isValid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructing_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
unique_ref<SomeClass> obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClass_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
unique_ref<SomeBaseClass> base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClass_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
unique_ref<SomeBaseClass> base = std::move(child);
EXPECT_FALSE(child.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToUniquePtr_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
SomeClass *obj1ptr = obj1.get();
std::unique_ptr<SomeClass> obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToUniquePtr_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::unique_ptr<SomeClass> obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassUniquePtr_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::unique_ptr<SomeBaseClass> base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassUniquePtr_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::unique_ptr<SomeBaseClass> base = std::move(child);
EXPECT_FALSE(child.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToSharedPtr_thenPointsToSameObject) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
SomeClass *obj1ptr = obj1.get();
std::shared_ptr<SomeClass> obj2 = std::move(obj1);
EXPECT_EQ(obj1ptr, obj2.get());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToSharedPtr_thenOldInstanceInvalid) {
unique_ref<SomeClass> obj1 = make_unique_ref<SomeClass>();
std::shared_ptr<SomeClass> obj2 = std::move(obj1);
EXPECT_FALSE(obj1.is_valid());
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassSharedPtr_thenPointsToSameObject) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::shared_ptr<SomeBaseClass> base = std::move(child);
EXPECT_EQ(3, base->v);
}
TEST_F(UniqueRefTest, givenUniqueRef_whenMoveConstructingToBaseClassSharedPtr_thenOldInstanceInvalid) {
unique_ref<SomeChildClass> child = make_unique_ref<SomeChildClass>(3);
std::shared_ptr<SomeBaseClass> base = std::move(child);
EXPECT_FALSE(child.is_valid());
}
TEST_F(UniqueRefTest, Swap) {
@ -177,7 +357,8 @@ TEST_F(UniqueRefTest, SwapFromInvalid) {
SomeClass *obj2ptr = obj2.get();
std::swap(obj1, obj2);
EXPECT_EQ(obj2ptr, obj1.get());
EXPECT_FALSE(obj2.isValid());
EXPECT_TRUE(obj1.is_valid());
EXPECT_FALSE(obj2.is_valid());
}
TEST_F(UniqueRefTest, SwapWithInvalid) {
@ -186,7 +367,8 @@ TEST_F(UniqueRefTest, SwapWithInvalid) {
makeInvalid(std::move(obj2));
SomeClass *obj1ptr = obj1.get();
std::swap(obj1, obj2);
EXPECT_FALSE(obj1.isValid());
EXPECT_FALSE(obj1.is_valid());
EXPECT_TRUE(obj2.is_valid());
EXPECT_EQ(obj1ptr, obj2.get());
}
@ -196,8 +378,8 @@ TEST_F(UniqueRefTest, SwapInvalidWithInvalid) {
makeInvalid(std::move(obj1));
makeInvalid(std::move(obj2));
std::swap(obj1, obj2);
EXPECT_FALSE(obj1.isValid());
EXPECT_FALSE(obj2.isValid());
EXPECT_FALSE(obj1.is_valid());
EXPECT_FALSE(obj2.is_valid());
}
TEST_F(UniqueRefTest, SwapFromRValue) {
@ -393,7 +575,7 @@ TEST_F(UniqueRefTest, NullptrIsLess2) {
unique_ref<int> var1 = make_unique_ref<int>(3);
unique_ref<int> var2 = make_unique_ref<int>(3);
makeInvalid(std::move(var2));
EXPECT_TRUE(std::less<unique_ref<int>>()(var2, var1));
EXPECT_FALSE(std::less<unique_ref<int>>()(var1, var2));
}
TEST_F(UniqueRefTest, NullptrIsNotLessThanNullptr) {
@ -404,6 +586,7 @@ TEST_F(UniqueRefTest, NullptrIsNotLessThanNullptr) {
EXPECT_FALSE(std::less<unique_ref<int>>()(var1, var2));
}
namespace {
class OnlyMoveable {
public:
OnlyMoveable(int value_): value(value_) {}
@ -413,10 +596,198 @@ public:
}
int value;
private:
DISALLOW_COPY_AND_ASSIGN(OnlyMoveable);
OnlyMoveable(const OnlyMoveable& rhs) = delete;
OnlyMoveable& operator=(const OnlyMoveable& rhs) = delete;
};
}
TEST_F(UniqueRefTest, AllowsDerefOnRvalue) {
OnlyMoveable val = *make_unique_ref<OnlyMoveable>(5);
EXPECT_EQ(OnlyMoveable(5), val);
}
}
namespace {
class DestructableMock final {
public:
DestructableMock(bool* wasDestructed): wasDestructed_(wasDestructed) {}
~DestructableMock() {
*wasDestructed_ = true;
}
private:
bool* wasDestructed_;
};
}
TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenDestructed_thenCallsDefaultDeleter) {
bool wasDestructed = false;
{
auto obj = make_unique_ref<DestructableMock>(&wasDestructed);
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenMoveConstructed_thenCallsDefaultDeleterAfterSecondDestructed) {
bool wasDestructed = false;
auto obj = make_unique_ref<DestructableMock>(&wasDestructed);
{
unique_ref<DestructableMock> obj2 = std::move(obj);
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenMoveAssigned_thenCallDefaultDeleterAfterSecondDestructed) {
bool dummy = false;
bool wasDestructed = false;
unique_ref<DestructableMock> obj = make_unique_ref<DestructableMock>(&wasDestructed);
{
unique_ref<DestructableMock> obj2 = make_unique_ref<DestructableMock>(&dummy);
obj2 = std::move(obj);
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithDefaultDeleter_whenDestructCalled_thenCallsDefaultDeleter) {
bool wasDestructed = false;
auto obj = make_unique_ref<DestructableMock>(&wasDestructed);
destruct(std::move(obj));
EXPECT_TRUE(wasDestructed);
EXPECT_FALSE(obj.is_valid());
}
namespace {
struct SetToTrueDeleter final {
void operator()(bool* ptr) {
*ptr = true;
}
};
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenDestructed_thenCallsCustomDeleter) {
bool wasDestructed = false;
{
auto obj = nullcheck(std::unique_ptr<bool, SetToTrueDeleter>(&wasDestructed)).value();
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenMoveConstructed_thenCallsCustomDeleterAfterSecondDestructed) {
bool wasDestructed = false;
unique_ref<bool, SetToTrueDeleter> obj = nullcheck(std::unique_ptr<bool, SetToTrueDeleter>(&wasDestructed)).value();
{
unique_ref<bool, SetToTrueDeleter> obj2 = std::move(obj);
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenMoveAssigned_thenCallsCustomDeleterAfterSecondDestructed) {
bool dummy = false;
bool wasDestructed = false;
unique_ref<bool, SetToTrueDeleter> obj = nullcheck(std::unique_ptr<bool, SetToTrueDeleter>(&wasDestructed)).value();
{
unique_ref<bool, SetToTrueDeleter> obj2 = nullcheck(std::unique_ptr<bool, SetToTrueDeleter>(&dummy)).value();
obj2 = std::move(obj);
EXPECT_FALSE(wasDestructed);
}
EXPECT_TRUE(wasDestructed);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDefaultConstructibleDeleter_whenDestructCalled_thenCallsCustomDeleter) {
bool wasDestructed = false;
auto obj = nullcheck(std::unique_ptr<bool, SetToTrueDeleter>(&wasDestructed)).value();
destruct(std::move(obj));
EXPECT_TRUE(wasDestructed);
EXPECT_FALSE(obj.is_valid());
}
namespace {
struct SetToDeleter final {
SetToDeleter(int value): value_(value) {}
int value_;
void operator()(int* ptr) {
*ptr = value_;
}
};
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenDestructed_thenCallsCustomDeleterInstance) {
int value = 0;
{
auto obj = nullcheck(std::unique_ptr<int, SetToDeleter>(&value, SetToDeleter(4))).value();
EXPECT_EQ(0, value);
}
EXPECT_EQ(4, value);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveConstructed_thenCallsCustomDeleterInstanceAfterSecondDestructed) {
int value = 0;
unique_ref<int, SetToDeleter> obj = nullcheck(std::unique_ptr<int, SetToDeleter>(&value, SetToDeleter(4))).value();
{
unique_ref<int, SetToDeleter> obj2 = std::move(obj);
EXPECT_EQ(0, value);
}
EXPECT_EQ(4, value);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveAssigned_thenCallsCustomDeleterInstanceAfterSecondDestructed) {
int dummy = 0;
int value = 0;
unique_ref<int, SetToDeleter> obj = nullcheck(std::unique_ptr<int, SetToDeleter>(&value, SetToDeleter(4))).value();
{
unique_ref<int, SetToDeleter> obj2 = nullcheck(std::unique_ptr<int, SetToDeleter>(&dummy, SetToDeleter(0))).value();
obj2 = std::move(obj);
EXPECT_EQ(0, value);
}
EXPECT_EQ(4, value);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenDestructCalled_thenCallsCustomDeleterInstance) {
int value = 0;
auto obj = nullcheck(std::unique_ptr<int, SetToDeleter>(&value, SetToDeleter(4))).value();
destruct(std::move(obj));
EXPECT_EQ(4, value);
EXPECT_FALSE(obj.is_valid());
}
TEST_F(UniqueRefTest, givenUniquePtrWithCustomDeleterInstance_whenMovedToUniquePtr_thenHasSameDeleterInstance) {
int dummy = 0;
SetToDeleter deleter(4);
auto ptr = std::unique_ptr<int, SetToDeleter>(&dummy, deleter);
auto ref = nullcheck(std::move(ptr)).value();
EXPECT_EQ(4, ref.get_deleter().value_);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveConstructing_thenHasSameDeleterInstance) {
int dummy = 0;
SetToDeleter deleter(4);
auto ref = nullcheck(std::unique_ptr<int, SetToDeleter>(&dummy, deleter)).value();
unique_ref<int, SetToDeleter> ref2 = std::move(ref);
EXPECT_EQ(4, ref2.get_deleter().value_);
}
TEST_F(UniqueRefTest, givenUniqueRefWithCustomDeleterInstance_whenMoveAssigning_thenHasSameDeleterInstance) {
int dummy = 0;
SetToDeleter deleter(4);
auto ref = nullcheck(std::unique_ptr<int, SetToDeleter>(&dummy, deleter)).value();
auto ref2 = nullcheck(std::unique_ptr<int, SetToDeleter>(&dummy, SetToDeleter(0))).value();
ref2 = std::move(ref);
EXPECT_EQ(4, ref2.get_deleter().value_);
}
TEST_F(UniqueRefTest, AllowsMoveConstructingToUniqueRefOfConst) {
unique_ref<int> a = make_unique_ref<int>(3);
unique_ref<const int> b = std::move(a);
}
TEST_F(UniqueRefTest, AllowsMoveAssigningToUniqueRefOfConst) {
unique_ref<int> a = make_unique_ref<int>(3);
unique_ref<const int> b = make_unique_ref<int>(10);
b = std::move(a);
}

2
vendor/README vendored
View File

@ -1,4 +1,4 @@
This directory contains external projects, taken from the following locations:
scrypt: http://www.tarsnap.com/scrypt.html
googletest: https://github.com/google/googletest/tree/release-1.8.0
spdlog: https://github.com/gabime/spdlog/tree/v0.11.0/include/spdlog
spdlog: https://github.com/gabime/spdlog/tree/v0.12.0/include/spdlog

View File

@ -30,11 +30,11 @@
#endif
#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#define SPDLOG_DEPRECATED __declspec(deprecated)
#else
#define DEPRECATED
#define SPDLOG_DEPRECATED
#endif
@ -57,7 +57,7 @@ using formatter_ptr = std::shared_ptr<spdlog::formatter>;
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using level_t = details::null_atomic_int;
#else
using level_t = std::atomic_int;
using level_t = std::atomic<int>;
#endif
using log_err_handler = std::function<void(const std::string &err_msg)>;

View File

@ -67,7 +67,7 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
{}
async_msg(async_msg_type m_type) :msg_type(m_type)
{};
{}
async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT
{
@ -82,7 +82,7 @@ async_msg(async_msg&& other) SPDLOG_NOEXCEPT:
// never copy or assign. should only be moved..
async_msg(const async_msg&) = delete;
async_msg& operator=(async_msg& other) = delete;
async_msg& operator=(const async_msg& other) = delete;
// construct from log_msg
async_msg(const details::log_msg& m) :
@ -229,8 +229,6 @@ inline spdlog::details::async_log_helper::~async_log_helper()
inline void spdlog::details::async_log_helper::log(const details::log_msg& msg)
{
push_msg(async_msg(msg));
}
inline void spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg)
@ -246,7 +244,6 @@ inline void spdlog::details::async_log_helper::push_msg(details::async_log_helpe
}
while (!_q.enqueue(std::move(new_msg)));
}
}
// optionally wait for the queue be empty and request flush from the sinks
@ -281,10 +278,8 @@ inline void spdlog::details::async_log_helper::worker_loop()
// return true if this thread should still be active (while no terminate msg was received)
inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush)
{
async_msg incoming_async_msg;
if (_q.dequeue(incoming_async_msg))
{
last_pop = details::os::now();
@ -359,8 +354,7 @@ inline void spdlog::details::async_log_helper::sleep_or_yield(const spdlog::log_
// yield upto 150 micros
if (time_since_op <= microseconds(100))
return yield();
return std::this_thread::yield();
// sleep for 20 ms upto 200 ms
if (time_since_op <= milliseconds(200))
@ -378,13 +372,7 @@ inline void spdlog::details::async_log_helper::wait_empty_q()
{
sleep_or_yield(details::os::now(), last_op);
}
}

View File

@ -31,13 +31,13 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name,
}
inline spdlog::async_logger::async_logger(const std::string& logger_name,
sinks_init_list sinks,
sinks_init_list sinks_list,
size_t queue_size,
const async_overflow_policy overflow_policy,
const std::function<void()>& worker_warmup_cb,
const std::chrono::milliseconds& flush_interval_ms,
const std::function<void()>& worker_teardown_cb) :
async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {}
async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb) {}
inline spdlog::async_logger::async_logger(const std::string& logger_name,
sink_ptr single_sink,

View File

@ -32,7 +32,7 @@ public:
const int open_interval = 10;
explicit file_helper() :
_fd(nullptr)
_fd(nullptr)
{}
file_helper(const file_helper&) = delete;
@ -89,7 +89,7 @@ public:
size_t msg_size = msg.formatted.size();
auto data = msg.formatted.data();
if (std::fwrite(data, 1, msg_size, _fd) != msg_size)
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
}
size_t size()
@ -112,7 +112,7 @@ public:
private:
FILE* _fd;
filename_t _filename;
filename_t _filename;
};
}
}

View File

@ -291,3 +291,8 @@ inline bool spdlog::logger::_should_flush_on(const details::log_msg &msg)
const auto flush_level = _flush_level.load(std::memory_order_relaxed);
return (msg.level >= flush_level) && (msg.level != level::off);
}
inline const std::vector<spdlog::sink_ptr>& spdlog::logger::sinks() const
{
return _sinks;
}

View File

@ -10,10 +10,12 @@
#include <ctime>
#include <functional>
#include <string>
#include <chrono>
#include <thread>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32
@ -25,27 +27,32 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <process.h> // _get_pid support
#include <io.h> // _get_osfhandle support
#ifdef __MINGW32__
#include <share.h>
#endif
#include <sys/types.h>
#else // unix
#elif __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <unistd.h>
#include <chrono>
#include <fcntl.h>
#ifdef __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#elif __FreeBSD__
#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
#else
#include <thread>
#endif
#endif //unix
#ifndef __has_feature // Clang - feature checking macros.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
namespace spdlog
{
namespace details
@ -135,6 +142,18 @@ inline bool operator!=(const std::tm& tm1, const std::tm& tm2)
SPDLOG_CONSTEXPR static const char* eol = SPDLOG_EOL;
SPDLOG_CONSTEXPR static int eol_size = sizeof(SPDLOG_EOL) - 1;
inline void prevent_child_fd(FILE *f)
{
#ifdef _WIN32
auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
throw spdlog_ex("SetHandleInformation failed", errno);
#else
auto fd = fileno(f);
if(fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
#endif
}
//fopen_s on non windows for writing
@ -146,13 +165,18 @@ inline int fopen_s(FILE** fp, const filename_t& filename, const filename_t& mode
#else
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);
#endif
return *fp == nullptr;
#else
#else //unix
*fp = fopen((filename.c_str()), mode.c_str());
return *fp == nullptr;
#endif
#ifdef SPDLOG_PREVENT_CHILD_FD
if(*fp != nullptr)
prevent_child_fd(*fp);
#endif
return *fp == nullptr;
}
inline int remove(const filename_t &filename)
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
@ -204,9 +228,9 @@ inline size_t filesize(FILE *f)
return st.st_size;
#else //windows 32 bits
struct _stat st;
if (_fstat(fd, &st) == 0)
return st.st_size;
long ret = _filelength(fd);
if (ret >= 0)
return static_cast<size_t>(ret);
#endif
#else // unix
@ -215,11 +239,11 @@ inline size_t filesize(FILE *f)
#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__))
struct stat64 st;
if (fstat64(fd, &st) == 0)
return st.st_size;
return static_cast<size_t>(st.st_size);
#else // unix 32 bits or osx
struct stat st;
if (fstat(fd, &st) == 0)
return st.st_size;
return static_cast<size_t>(st.st_size);
#endif
#endif
throw spdlog_ex("Failed getting file size from fd", errno);
@ -292,7 +316,7 @@ inline int utc_minutes_offset(const std::tm& tm = details::os::localtime())
//Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline size_t thread_id()
inline size_t _thread_id()
{
#ifdef _WIN32
return static_cast<size_t>(::GetCurrentThreadId());
@ -308,10 +332,21 @@ inline size_t thread_id()
#else //Default to standard C++11 (OSX and other Unix)
return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
#endif
}
//Return current thread id as size_t (from thread local storage)
inline size_t thread_id()
{
#if defined(_MSC_VER) && (_MSC_VER < 1900) || defined(__clang__) && !__has_feature(cxx_thread_local)
return _thread_id();
#else
static thread_local const size_t tid = _thread_id();
return tid;
#endif
}
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
@ -342,8 +377,8 @@ inline std::string errno_str(int err_num)
else
return "Unkown error";
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || \
((_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE) // posix version
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(ANDROID) || defined(__SUNPRO_CC) || \
((_POSIX_C_SOURCE >= 200112L) && ! defined(_GNU_SOURCE)) // posix version
if (strerror_r(err_num, buf, buf_size) == 0)
return std::string(buf);
@ -355,6 +390,17 @@ inline std::string errno_str(int err_num)
#endif
}
inline int pid()
{
#ifdef _WIN32
return ::_getpid();
#else
return static_cast<int>(::getpid());
#endif
}
} //os
} //details
} //spdlog

View File

@ -18,6 +18,7 @@
#include <thread>
#include <utility>
#include <vector>
#include <array>
namespace spdlog
{
@ -78,42 +79,60 @@ static int to12h(const tm& t)
}
//Abbreviated weekday name
static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
using days_array = std::array<std::string, 7>;
static const days_array& days()
{
static const days_array arr{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
return arr;
}
class a_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm& tm_time) override
{
msg.formatted << days[tm_time.tm_wday];
msg.formatted << days()[tm_time.tm_wday];
}
};
//Full weekday name
static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
static const days_array& full_days()
{
static const days_array arr{ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
return arr;
}
class A_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm& tm_time) override
{
msg.formatted << full_days[tm_time.tm_wday];
msg.formatted << full_days()[tm_time.tm_wday];
}
};
//Abbreviated month
static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
using months_array = std::array<std::string, 12>;
static const months_array& months()
{
static const months_array arr{ "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" };
return arr;
}
class b_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm& tm_time) override
{
msg.formatted << months[tm_time.tm_mon];
msg.formatted << months()[tm_time.tm_mon];
}
};
//Full month name
static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
static const months_array& full_months()
{
static const months_array arr{ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
return arr;
}
class B_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm& tm_time) override
{
msg.formatted << full_months[tm_time.tm_mon];
msg.formatted << full_months()[tm_time.tm_mon];
}
};
@ -138,7 +157,7 @@ class c_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm& tm_time) override
{
msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
msg.formatted << days()[tm_time.tm_wday] << ' ' << months()[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';
pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;
}
};
@ -356,7 +375,7 @@ private:
//Thread id
// Thread id
class t_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm&) override
@ -365,6 +384,15 @@ class t_formatter:public flag_formatter
}
};
// Current pid
class pid_formatter:public flag_formatter
{
void format(details::log_msg& msg, const std::tm&) override
{
msg.formatted << details::os::pid();
}
};
class v_formatter:public flag_formatter
{
@ -453,6 +481,8 @@ class full_formatter:public flag_formatter
}
};
}
}
///////////////////////////////////////////////////////////////////////////////
@ -611,6 +641,10 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::full_formatter()));
break;
case ('P'):
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::pid_formatter()));
break;
default: //Unkown flag appears as is
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter('%')));
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::ch_formatter(flag)));

View File

@ -12,9 +12,20 @@
#include <spdlog/details/registry.h>
#include <spdlog/sinks/file_sinks.h>
#include <spdlog/sinks/stdout_sinks.h>
#ifdef SPDLOG_ENABLE_SYSLOG
#include <spdlog/sinks/syslog_sink.h>
#endif
#ifdef _WIN32
#include <spdlog/sinks/wincolor_sink.h>
#else
#include <spdlog/sinks/ansicolor_sink.h>
#endif
#ifdef __ANDROID__
#include <spdlog/sinks/android_sink.h>
#endif
#include <chrono>
#include <functional>
@ -69,34 +80,86 @@ inline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(const std::string
return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, SPDLOG_FILENAME_T("txt"), hour, minute);
}
// Create stdout/stderr loggers (with optinal color support)
inline std::shared_ptr<spdlog::logger> create_console_logger(const std::string& logger_name, spdlog::sink_ptr sink, bool color)
//
// stdout/stderr loggers
//
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name)
{
if (color) //use color wrapper sink
sink = std::make_shared<spdlog::sinks::ansicolor_sink>(sink);
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name)
{
return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());
}
//
// stdout/stderr color loggers
//
#ifdef _WIN32
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>();
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string& logger_name, bool color)
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string& logger_name)
{
return create_console_logger(logger_name, sinks::stdout_sink_mt::instance(), color);
auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_st>();
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string& logger_name, bool color)
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string& logger_name)
{
return create_console_logger(logger_name, sinks::stdout_sink_st::instance(), color);
auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_mt>();
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string& logger_name, bool color)
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string& logger_name)
{
return create_console_logger(logger_name, sinks::stderr_sink_mt::instance(), color);
auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>();
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string& logger_name, bool color)
#else //ansi terminal colors
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string& logger_name)
{
return create_console_logger(logger_name, sinks::stderr_sink_st::instance(), color);
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stdout_sink_mt::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stdout_sink_st::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stderr_sink_mt::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
inline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string& logger_name)
{
auto sink = std::make_shared<spdlog::sinks::ansicolor_sink>(spdlog::sinks::stderr_sink_st::instance());
return spdlog::details::registry::instance().create(logger_name, sink);
}
#endif
#ifdef SPDLOG_ENABLE_SYSLOG
// Create syslog logger
inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option)
@ -105,7 +168,7 @@ inline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(const std::string&
}
#endif
#if defined(__ANDROID__)
#ifdef __ANDROID__
inline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string& logger_name, const std::string& tag)
{
return create<spdlog::sinks::android_sink>(logger_name, tag);

View File

@ -1,33 +1,31 @@
/*
Formatting library for C++
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Commented out by spdlog to use header only
// #include "fmt/format.h"
// #include "fmt/printf.h"
#include "format.h"
#include <string.h>
@ -73,31 +71,37 @@ using fmt::internal::Arg;
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>();
static inline fmt::internal::Null<> strerror_r(int, char *, ...)
{
return fmt::internal::Null<>();
}
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>();
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...)
{
return fmt::internal::Null<>();
}
namespace fmt {
FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {}
FMT_FUNC FormatError::~FormatError() throw() {}
FMT_FUNC SystemError::~SystemError() throw() {}
FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT
{}
FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT
{}
FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT
{}
namespace {
namespace {
#ifndef _MSC_VER
# define FMT_SNPRINTF snprintf
#else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...)
{
va_list args;
va_start(args, format);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
va_end(args);
return result;
}
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
@ -107,166 +111,183 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
const char RESET_COLOR[] = "\x1b[0m";
const char RESET_COLOR[] = "\x1b[0m";
typedef void (*FormatFunc)(Writer &, int, StringRef);
typedef void(*FormatFunc)(Writer &, int, StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
// This can be either a pointer to a string stored in buffer,
// or a pointer to some static immutable string.
// Returns one of the following values:
// 0 - success
// ERANGE - buffer is not large enough to store the error message
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT
{
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
class StrError {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
class StrError
{
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &) {}
// A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &)
{}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result) {
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int result)
{
// glibc versions before 2.13 return result in errno.
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the result of GNU-specific version of strerror_r.
int handle(char *message)
{
// If the buffer is full then the message is probably truncated.
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Handle the case when strerror_r is not available.
int handle(internal::Null<>)
{
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result)
{
// If the buffer is full then the message is probably truncated.
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>)
{
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
public:
StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
public:
StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size)
{}
int run() {
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return StrError(error_code, buffer, buffer_size).run();
}
int run()
{
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_));
}
};
return StrError(error_code, buffer, buffer_size).run();
}
void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
}
void format_error_code(Writer &out, int error_code,
StringRef message) FMT_NOEXCEPT
{
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::IntTraits<int>::MainType MainType;
MainType abs_value = static_cast<MainType>(error_code);
if (internal::is_negative(error_code)) {
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERROR_STR << error_code;
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
}
void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT {
MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
void report_error(FormatFunc func, int error_code,
StringRef message) FMT_NOEXCEPT
{
MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr);
}
} // namespace
namespace internal {
namespace internal {
// This method is used to preserve binary compatibility with fmt 3.0.
// It can be removed in 4.0.
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
fmt::format_system_error(out, error_code, message);
}
} // namespace internal
// This method is used to preserve binary compatibility with fmt 3.0.
// It can be removed in 4.0.
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
fmt::format_system_error(out, error_code, message);
}
} // namespace internal
FMT_FUNC void SystemError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
FMT_FUNC void SystemError::init(
int err_code, CStringRef format_str, ArgList args)
{
error_code_ = err_code;
MemoryWriter w;
format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
template <typename T>
int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value)
{
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value)
{
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
const char internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
template <typename T>
const char internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, \
@ -279,274 +300,279 @@ const char internal::BasicData<T>::DIGITS[] =
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template <typename T>
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant
// to avoid warnings about C++98 not supporting long long.
ULongLong(1000000000) * ULongLong(1000000000) * 10
};
template <typename T>
const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant
// to avoid warnings about C++98 not supporting long long.
ULongLong(1000000000) * ULongLong(1000000000) * 10
};
FMT_FUNC void internal::report_unknown_type(char code, const char *type) {
(void)type;
if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(FormatError(
format("unknown format code '{}' for {}", code, type)));
}
FMT_THROW(FormatError(
format("unknown format code '\\x{:02x}' for {}",
static_cast<unsigned>(code), type)));
}
FMT_FUNC void internal::report_unknown_type(char code, const char *type)
{
(void)type;
if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(FormatError(
format("unknown format code '{}' for {}", code, type)));
}
FMT_THROW(FormatError(
format("unknown format code '\\x{:02x}' for {}",
static_cast<unsigned>(code), type)));
}
#if FMT_USE_WINDOWS_H
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s)
{
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (s.size() > INT_MAX)
FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));
int s_size = static_cast<int>(s.size());
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {
if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s)
{
if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s)
{
if (s.size() > INT_MAX)
return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void WindowsError::init(
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
FMT_FUNC void WindowsError::init(
int err_code, CStringRef format_str, ArgList args)
{
error_code_ = err_code;
MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this;
base = std::runtime_error(w.str());
}
FMT_FUNC void internal::format_windows_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), 0);
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
FMT_FUNC void internal::format_windows_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
FMT_TRY{
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
wchar_t *system_message = &buffer[0];
int result = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...)
{}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
#endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {
FMT_TRY {
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
FMT_FUNC void format_system_error(
Writer &out, int error_code, StringRef message) FMT_NOEXCEPT
{
FMT_TRY{
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;
buffer.resize(internal::INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...)
{}
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
}
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = 0;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args)
{
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t)
{
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC Arg internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) {
Arg arg = args_[arg_index];
switch (arg.type) {
case Arg::NONE:
error = "argument index out of range";
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
break;
default:
/*nothing*/;
}
return arg;
}
FMT_FUNC Arg internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error)
{
Arg arg = args_[arg_index];
switch (arg.type) {
case Arg::NONE:
error = "argument index out of range";
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
break;
default:
/*nothing*/;
}
return arg;
}
FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message);
}
FMT_FUNC void report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT
{
// 'fmt::' is for bcc32.
report_error(format_system_error, error_code, message);
}
#if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
// 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message);
}
FMT_FUNC void report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT
{
// 'fmt::' is for bcc32.
report_error(internal::format_windows_error, error_code, message);
}
#endif
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f);
}
FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args)
{
MemoryWriter w;
w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f);
}
FMT_FUNC void print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
FMT_FUNC void print(CStringRef format_str, ArgList args)
{
print(stdout, format_str, args);
}
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
print(format, args);
std::fputs(RESET_COLOR, stdout);
}
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);
FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
std::size_t size = w.size();
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args)
{
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
print(format, args);
std::fputs(RESET_COLOR, stdout);
}
#ifndef FMT_HEADER_ONLY
template struct internal::BasicData<void>;
template struct internal::BasicData<void>;
// Explicit instantiations for char.
// Explicit instantiations for char.
template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args);
template void internal::ArgMap<char>::init(const ArgList &args);
template void PrintfFormatter<char>::format(CStringRef format);
template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
template int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t.
// Explicit instantiations for wchar_t.
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template void PrintfFormatter<wchar_t>::format(WCStringRef format);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
template int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
#endif // FMT_HEADER_ONLY

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +1,37 @@
/*
Formatting library for C++ - std::ostream support
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
For the license information refer to format.h.
*/
// Commented out by spdlog to use header only
// #include "fmt/ostream.h"
#include "ostream.h"
namespace fmt {
namespace internal {
FMT_FUNC void write(std::ostream &os, Writer &w) {
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
}
namespace internal {
FMT_FUNC void write(std::ostream &os, Writer &w)
{
const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size();
UnsignedStreamSize max_size =
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do {
UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n));
data += n;
size -= n;
} while (size != 0);
}
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
internal::write(os, w);
}
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args)
{
MemoryWriter w;
w.write(format_str, args);
internal::write(os, w);
}
} // namespace fmt

View File

@ -1,17 +1,17 @@
/*
Formatting library for C++ - std::ostream support
Formatting library for C++ - std::ostream support
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
For the license information refer to format.h.
*/
#ifndef FMT_OSTREAM_H_
#define FMT_OSTREAM_H_
// Commented out by spdlog to use header only
// #include "fmt/format.h"
// commented out by spdlog
// #include "format.h"
#include <ostream>
namespace fmt
@ -21,7 +21,7 @@ namespace internal
{
template <class Char>
class FormatBuf : public std::basic_streambuf<Char>
class FormatBuf: public std::basic_streambuf<Char>
{
private:
typedef typename std::basic_streambuf<Char>::int_type int_type;
@ -31,7 +31,7 @@ private:
Char *start_;
public:
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0])
FormatBuf(Buffer<Char> &buffer): buffer_(buffer), start_(&buffer[0])
{
this->setp(start_, start_ + buffer_.capacity());
}
@ -46,7 +46,7 @@ public:
start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
this->setp(start_ + buf_size + 1, start_ + buf_size * 2);
}
return ch;
}
@ -59,7 +59,7 @@ public:
Yes &convert(std::ostream &);
struct DummyStream : std::ostream
struct DummyStream: std::ostream
{
DummyStream(); // Suppress a bogus warning in MSVC.
// Hide all operator<< overloads from std::ostream.
@ -99,14 +99,14 @@ void format_arg(BasicFormatter<Char, ArgFormatter> &f,
}
/**
\rst
Prints formatted data to the stream *os*.
\rst
Prints formatted data to the stream *os*.
**Example**::
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
print(cerr, "Don't {}!", "panic");
\endrst
*/
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
} // namespace fmt

View File

@ -1,11 +1,11 @@
/*
Formatting library for C++
Formatting library for C++
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
For the license information refer to format.h.
*/
#ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_
@ -13,7 +13,7 @@
#include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits
#include "fmt/ostream.h"
#include "ostream.h"
namespace fmt
{
@ -52,7 +52,7 @@ struct IntChecker<true>
}
};
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int>
class PrecisionHandler: public ArgVisitor<PrecisionHandler, int>
{
public:
void report_unhandled_arg()
@ -70,7 +70,7 @@ public:
};
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public ArgVisitor<IsZeroInt, bool>
class IsZeroInt: public ArgVisitor<IsZeroInt, bool>
{
public:
template <typename T>
@ -83,13 +83,19 @@ public:
template <typename T, typename U>
struct is_same
{
enum { value = 0 };
enum
{
value = 0
};
};
template <typename T>
struct is_same<T, T>
{
enum { value = 1 };
enum
{
value = 1
};
};
// An argument visitor that converts an integer argument to T for printf,
@ -97,7 +103,7 @@ struct is_same<T, T>
// corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned)
template <typename T = void>
class ArgConverter : public ArgVisitor<ArgConverter<T>, void>
class ArgConverter: public ArgVisitor<ArgConverter<T>, void>
{
private:
internal::Arg &arg_;
@ -107,7 +113,8 @@ private:
public:
ArgConverter(internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {}
: arg_(arg), type_(type)
{}
void visit_bool(bool value)
{
@ -158,7 +165,7 @@ public:
};
// Converts an integer argument to char for printf.
class CharConverter : public ArgVisitor<CharConverter, void>
class CharConverter: public ArgVisitor<CharConverter, void>
{
private:
internal::Arg &arg_;
@ -166,7 +173,8 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
explicit CharConverter(internal::Arg &arg): arg_(arg)
{}
template <typename T>
void visit_any_int(T value)
@ -178,7 +186,7 @@ public:
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class WidthHandler : public ArgVisitor<WidthHandler, unsigned>
class WidthHandler: public ArgVisitor<WidthHandler, unsigned>
{
private:
FormatSpec &spec_;
@ -186,7 +194,8 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public:
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
explicit WidthHandler(FormatSpec &spec): spec_(spec)
{}
void report_unhandled_arg()
{
@ -212,24 +221,24 @@ public:
} // namespace internal
/**
\rst
A ``printf`` argument formatter based on the `curiously recurring template
pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
\rst
A ``printf`` argument formatter based on the `curiously recurring template
pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
or all of the visit methods with the same signatures as the methods in
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. When a formatting
function processes an argument, it will dispatch to a visit method
specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
superclass will be called.
\endrst
*/
To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some
or all of the visit methods with the same signatures as the methods in
`~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.
Pass the subclass as the *Impl* template parameter. When a formatting
function processes an argument, it will dispatch to a visit method
specific to the argument type. For example, if the argument type is
``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass
will be called. If the subclass doesn't contain a method with this signature,
then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its
superclass will be called.
\endrst
*/
template <typename Impl, typename Char>
class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char>
class BasicPrintfArgFormatter: public internal::ArgFormatterBase<Impl, Char>
{
private:
void write_null_pointer()
@ -242,14 +251,15 @@ private:
public:
/**
\rst
Constructs an argument formatter object.
*writer* is a reference to the output writer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec)
: internal::ArgFormatterBase<Impl, Char>(writer, spec) {}
\rst
Constructs an argument formatter object.
*writer* is a reference to the output writer and *spec* contains format
specifier information for standard argument types.
\endrst
*/
BasicPrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: internal::ArgFormatterBase<Impl, Char>(w, s)
{}
/** Formats an argument of type ``bool``. */
void visit_bool(bool value)
@ -315,7 +325,7 @@ public:
void visit_custom(internal::Arg::CustomValue c)
{
BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0};
const Char format_str[] = { '}', 0 };
const Char *format = format_str;
c.format(&formatter, c.value, &format);
}
@ -329,12 +339,13 @@ class PrintfArgFormatter
public:
/** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s)
{}
};
/** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
class PrintfFormatter : private internal::FormatterBase
class PrintfFormatter: private internal::FormatterBase
{
private:
BasicWriter<Char> &writer_;
@ -352,14 +363,15 @@ private:
public:
/**
\rst
Constructs a ``PrintfFormatter`` object. References to the arguments and
the writer are stored in the formatter object so make sure they have
appropriate lifetimes.
\endrst
*/
explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w)
: FormatterBase(args), writer_(w) {}
\rst
Constructs a ``PrintfFormatter`` object. References to the arguments and
the writer are stored in the formatter object so make sure they have
appropriate lifetimes.
\endrst
*/
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
: FormatterBase(al), writer_(w)
{}
/** Formats stored arguments and writes the output to the writer. */
FMT_API void format(BasicCStringRef<Char> format_str);
@ -399,7 +411,7 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index)
{
(void)s;
const char *error = 0;
const char *error = FMT_NULL;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
if (error)
@ -569,13 +581,13 @@ void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args)
}
/**
\rst
Formats arguments and returns the result as a string.
\rst
Formats arguments and returns the result as a string.
**Example**::
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
inline std::string sprintf(CStringRef format, ArgList args)
{
@ -594,26 +606,26 @@ inline std::wstring sprintf(WCStringRef format, ArgList args)
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
/**
\rst
Prints formatted data to the file *f*.
\rst
Prints formatted data to the file *f*.
**Example**::
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
/**
\rst
Prints formatted data to ``stdout``.
\rst
Prints formatted data to ``stdout``.
**Example**::
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline int printf(CStringRef format, ArgList args)
{
return fprintf(stdout, format, args);
@ -621,14 +633,14 @@ inline int printf(CStringRef format, ArgList args)
FMT_VARIADIC(int, printf, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
\rst
Prints formatted data to the stream *os*.
**Example**::
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
{
MemoryWriter w;
@ -639,4 +651,8 @@ inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt
#ifdef FMT_HEADER_ONLY
# include "printf.cc"
#endif
#endif // FMT_PRINTF_H_

View File

@ -5,7 +5,7 @@
#pragma once
// Thread safe logger
// Thread safe logger (except for set_pattern(..), set_formatter(..) and set_error_handler())
// Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
@ -68,6 +68,8 @@ public:
virtual void flush();
const std::vector<sink_ptr>& sinks() const;
protected:
virtual void _sink_it(details::log_msg&);
virtual void _set_pattern(const std::string&);
@ -90,5 +92,3 @@ protected:
}
#include <spdlog/details/logger_impl.h>

View File

@ -33,7 +33,7 @@ public:
virtual void log(const details::log_msg& msg) override;
virtual void flush() override;
void set_color(level::level_enum level, const std::string& color);
void set_color(level::level_enum color_level, const std::string& color);
/// Formatting codes
const std::string reset = "\033[00m";
@ -101,9 +101,9 @@ inline void ansicolor_sink::flush()
sink_->flush();
}
inline void ansicolor_sink::set_color(level::level_enum level, const std::string& color)
inline void ansicolor_sink::set_color(level::level_enum color_level, const std::string& color)
{
colors_[level] = color;
colors_[color_level] = color;
}
inline ansicolor_sink::~ansicolor_sink()

View File

@ -29,7 +29,7 @@ template<class Mutex>
class simple_file_sink : public base_sink < Mutex >
{
public:
explicit simple_file_sink(const filename_t &filename, bool truncate = false)
explicit simple_file_sink(const filename_t &filename, bool truncate = false):_force_flush(false)
{
_file_helper.open(filename, truncate);
}
@ -37,14 +37,21 @@ public:
{
_file_helper.flush();
}
void set_force_flush(bool force_flush)
{
_force_flush = force_flush;
}
protected:
void _sink_it(const details::log_msg& msg) override
{
_file_helper.write(msg);
if(_force_flush)
_file_helper.flush();
}
private:
details::file_helper _file_helper;
bool _force_flush;
};
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
@ -183,7 +190,7 @@ public:
int rotation_minute) : _base_filename(base_filename),
_extension(extension),
_rotation_h(rotation_hour),
_rotation_m(rotation_minute)
_rotation_m(rotation_minute)
{
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");

View File

@ -27,7 +27,7 @@ protected:
};
typedef null_sink<details::null_mutex> null_sink_st;
typedef null_sink<std::mutex> null_sink_mt;
typedef null_sink<details::null_mutex> null_sink_mt;
}
}

View File

@ -15,7 +15,10 @@ namespace sinks
class sink
{
public:
sink(): _level( level::trace ) {}
sink()
{
_level = level::trace;
}
virtual ~sink() {}
virtual void log(const details::log_msg& msg) = 0;

View File

@ -18,11 +18,12 @@ namespace sinks
{
template <class Mutex>
class stdout_sink : public base_sink<Mutex>
class stdout_sink: public base_sink<Mutex>
{
using MyType = stdout_sink<Mutex>;
public:
stdout_sink() {}
stdout_sink()
{}
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
@ -46,11 +47,12 @@ typedef stdout_sink<std::mutex> stdout_sink_mt;
template <class Mutex>
class stderr_sink : public base_sink<Mutex>
class stderr_sink: public base_sink<Mutex>
{
using MyType = stderr_sink<Mutex>;
public:
stderr_sink() {}
stderr_sink()
{}
static std::shared_ptr<MyType> instance()
{
static std::shared_ptr<MyType> instance = std::make_shared<MyType>();

View File

@ -0,0 +1,116 @@
//
// Copyright(c) 2016 spdlog
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/common.h>
#include <mutex>
#include <string>
#include <map>
#include <wincon.h>
namespace spdlog
{
namespace sinks
{
/*
* Windows color console sink. Uses WriteConsoleA to write to the console with colors
*/
template<class Mutex>
class wincolor_sink: public base_sink<Mutex>
{
public:
const WORD BOLD = FOREGROUND_INTENSITY;
const WORD RED = FOREGROUND_RED;
const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;
wincolor_sink(HANDLE std_handle): out_handle_(std_handle)
{
colors_[level::trace] = CYAN;
colors_[level::debug] = CYAN;
colors_[level::info] = WHITE | BOLD;
colors_[level::warn] = YELLOW | BOLD;
colors_[level::err] = RED | BOLD; // red bold
colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background
colors_[level::off] = 0;
}
virtual ~wincolor_sink()
{
flush();
}
wincolor_sink(const wincolor_sink& other) = delete;
wincolor_sink& operator=(const wincolor_sink& other) = delete;
virtual void _sink_it(const details::log_msg& msg) override
{
auto color = colors_[msg.level];
auto orig_attribs = set_console_attribs(color);
WriteConsoleA(out_handle_, msg.formatted.data(), static_cast<DWORD>(msg.formatted.size()), nullptr, nullptr);
SetConsoleTextAttribute(out_handle_, orig_attribs); //reset to orig colors
}
virtual void flush() override
{
// windows console always flushed?
}
// change the color for the given level
void set_color(level::level_enum level, WORD color)
{
std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);
colors_[level] = color;
}
private:
HANDLE out_handle_;
std::map<level::level_enum, WORD> colors_;
// set color and return the orig console attributes (for resetting later)
WORD set_console_attribs(WORD attribs)
{
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);
SetConsoleTextAttribute(out_handle_, attribs);
return orig_buffer_info.wAttributes; //return orig attribs
}
};
//
// windows color console to stdout
//
template<class Mutex>
class wincolor_stdout_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stdout_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE))
{}
};
typedef wincolor_stdout_sink<std::mutex> wincolor_stdout_sink_mt;
typedef wincolor_stdout_sink<details::null_mutex> wincolor_stdout_sink_st;
//
// windows color console to stderr
//
template<class Mutex>
class wincolor_stderr_sink: public wincolor_sink<Mutex>
{
public:
wincolor_stderr_sink() : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE))
{}
};
typedef wincolor_stderr_sink<std::mutex> wincolor_stderr_sink_mt;
typedef wincolor_stderr_sink<details::null_mutex> wincolor_stderr_sink_st;
}
}

View File

@ -2,12 +2,13 @@
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// spdlog main header file.
// see example.cpp for usage example
#pragma once
#define SPDLOG_VERSION "0.12.0"
#include <spdlog/tweakme.h>
#include <spdlog/common.h>
#include <spdlog/logger.h>
@ -88,10 +89,17 @@ std::shared_ptr<logger> daily_logger_st(const std::string& logger_name, const fi
//
// Create and register stdout/stderr loggers
//
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name, bool color = false);
std::shared_ptr<logger> stdout_logger_mt(const std::string& logger_name);
std::shared_ptr<logger> stdout_logger_st(const std::string& logger_name);
std::shared_ptr<logger> stderr_logger_mt(const std::string& logger_name);
std::shared_ptr<logger> stderr_logger_st(const std::string& logger_name);
//
// Create and register colored stdout/stderr loggers
//
std::shared_ptr<logger> stdout_color_mt(const std::string& logger_name);
std::shared_ptr<logger> stdout_color_st(const std::string& logger_name);
std::shared_ptr<logger> stderr_color_mt(const std::string& logger_name);
std::shared_ptr<logger> stderr_color_st(const std::string& logger_name);
//

View File

@ -101,3 +101,8 @@
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent child processes from inheriting log file descriptors
//
// #define SPDLOG_PREVENT_CHILD_FD
///////////////////////////////////////////////////////////////////////////////