Add macros.h, pointer.h and optional_ownership_pointer.h
This commit is contained in:
parent
60bed8635e
commit
a01a6f64d1
97
CMakeLists.txt
Normal file
97
CMakeLists.txt
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
INCLUDE(messmer/cmake/tools)
|
||||||
|
|
||||||
|
# Initializes block variables
|
||||||
|
INIT_BIICODE_BLOCK()
|
||||||
|
|
||||||
|
SETUP_GOOGLETEST()
|
||||||
|
|
||||||
|
# Actually create targets: EXEcutables and libraries.
|
||||||
|
ADD_BIICODE_TARGETS()
|
||||||
|
|
||||||
|
ACTIVATE_CPP14()
|
||||||
|
|
||||||
|
# You can safely delete lines from here...
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# REFERENCE #
|
||||||
|
###############################################################################
|
||||||
|
#
|
||||||
|
# This CMakeLists.txt file helps defining your block building and compiling
|
||||||
|
# To learn more about the CMake use with biicode, visit http://docs.biicode.com/c++.html
|
||||||
|
#
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# NEW FEATURE! Include cmake files from remote blocks:
|
||||||
|
# -----------------------------------------------------
|
||||||
|
# Now you can handle cmake dependencies alike you do with c/c++:
|
||||||
|
#
|
||||||
|
# INCLUDE(user/block/myrecipe) # include myrecipe.cmake from remote user/block
|
||||||
|
#
|
||||||
|
# > EXAMPLE: Include our recipes and activate C++11 in your block (http://www.biicode.com/biicode/cmake)
|
||||||
|
#
|
||||||
|
# INCLUDE(biicode/cmake/tools) # Include tools.cmake file from "cmake" block from the "biicode" user
|
||||||
|
# ACTIVATE_CPP11(INTERFACE ${BII_BLOCK_TARGET})
|
||||||
|
#
|
||||||
|
# Remember to run "bii find" to download out cmake tools file
|
||||||
|
#
|
||||||
|
# ---------------------
|
||||||
|
# INIT_BIICODE_BLOCK()
|
||||||
|
# ---------------------
|
||||||
|
# This function creates several helper variables as ${BII_BLOCK_NAME} and ${BII_BLOCK_USER}
|
||||||
|
# Also it loads variables from the cmake/bii_user_block_vars.cmake
|
||||||
|
# ${BII_LIB_SRC} File list to create the library
|
||||||
|
# ${BII_LIB_TYPE} Empty (default, STATIC most casess) STATIC or SHARED
|
||||||
|
# ${BII_LIB_DEPS} Dependencies to other libraries (user2_block2, user3_blockX)
|
||||||
|
# ${BII_LIB_SYSTEM_HEADERS} System linking requirements as windows.h, pthread.h, etc
|
||||||
|
#
|
||||||
|
# You can use or modify them here, for example, to add or remove files from targets based on OS
|
||||||
|
# Or use typical cmake configurations done BEFORE defining targets. Examples:
|
||||||
|
# ADD_DEFINITIONS(-DFOO)
|
||||||
|
# FIND_PACKAGE(OpenGL QUIET)
|
||||||
|
# You can add INCLUDE_DIRECTORIES here too
|
||||||
|
#
|
||||||
|
# ---------------------
|
||||||
|
# ADD_BIICODE_TARGETS()
|
||||||
|
# ---------------------
|
||||||
|
#
|
||||||
|
# This function creates the following variables:
|
||||||
|
# ${BII_BLOCK_TARGET} Interface (no files) target for convenient configuration of all
|
||||||
|
# targets in this block, as the rest of targets always depend on it
|
||||||
|
# has name in the form "user_block_interface"
|
||||||
|
# ${BII_LIB_TARGET} Target library name, usually in the form "user_block". May not exist
|
||||||
|
# if BII_LIB_SRC is empty
|
||||||
|
# ${BII_BLOCK_TARGETS} List of all targets defined in this block
|
||||||
|
# ${BII_BLOCK_EXES} List of executables targets defined in this block
|
||||||
|
# ${BII_exe_name_TARGET}: Executable target (e.g. ${BII_main_TARGET}. You can also use
|
||||||
|
# directly the name of the executable target (e.g. user_block_main)
|
||||||
|
#
|
||||||
|
# > EXAMPLE: Add include directories to all targets of this block
|
||||||
|
#
|
||||||
|
# TARGET_INCLUDE_DIRECTORIES(${BII_BLOCK_TARGET} INTERFACE myincludedir)
|
||||||
|
#
|
||||||
|
# You can add private include directories to the Lib (if existing)
|
||||||
|
#
|
||||||
|
# > EXAMPLE: Link with pthread:
|
||||||
|
#
|
||||||
|
# TARGET_LINK_LIBRARIES(${BII_BLOCK_TARGET} INTERFACE pthread)
|
||||||
|
# or link against library:
|
||||||
|
# TARGET_LINK_LIBRARIES(${BII_LIB_TARGET} PUBLIC pthread)
|
||||||
|
# or directly use the library target name:
|
||||||
|
# TARGET_LINK_LIBRARIES(user_block PUBLIC pthread)
|
||||||
|
#
|
||||||
|
# NOTE: This can be also done adding pthread to ${BII_LIB_DEPS}
|
||||||
|
# BEFORE calling ADD_BIICODE_TARGETS()
|
||||||
|
#
|
||||||
|
# > EXAMPLE: how to activate C++11
|
||||||
|
#
|
||||||
|
# IF(APPLE)
|
||||||
|
# TARGET_COMPILE_OPTIONS(${BII_BLOCK_TARGET} INTERFACE "-std=c++11 -stdlib=libc++")
|
||||||
|
# ELSEIF (WIN32 OR UNIX)
|
||||||
|
# TARGET_COMPILE_OPTIONS(${BII_BLOCK_TARGET} INTERFACE "-std=c++11")
|
||||||
|
# ENDIF(APPLE)
|
||||||
|
#
|
||||||
|
# > EXAMPLE: Set properties to target
|
||||||
|
#
|
||||||
|
# SET_TARGET_PROPERTIES(${BII_BLOCK_TARGET} PROPERTIES COMPILE_DEFINITIONS "IOV_MAX=255")
|
||||||
|
#
|
||||||
|
|
||||||
|
|
44
biicode.conf
Normal file
44
biicode.conf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Biicode configuration file
|
||||||
|
|
||||||
|
[requirements]
|
||||||
|
google/gtest: 10
|
||||||
|
messmer/cmake: 0
|
||||||
|
|
||||||
|
[parent]
|
||||||
|
# The parent version of this block. Must match folder name. E.g.
|
||||||
|
# user/block # No version number means not published yet
|
||||||
|
# You can change it to publish to a different track, and change version, e.g.
|
||||||
|
# user/block(track): 7
|
||||||
|
|
||||||
|
[paths]
|
||||||
|
# Local directories to look for headers (within block)
|
||||||
|
# /
|
||||||
|
# include
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=)
|
||||||
|
# hello.h + hello_imp.cpp hello_imp2.cpp
|
||||||
|
# *.h + *.cpp
|
||||||
|
|
||||||
|
test/main.cpp + test/*.cpp
|
||||||
|
|
||||||
|
[mains]
|
||||||
|
# Manual adjust of files that define an executable
|
||||||
|
# !main.cpp # Do not build executable from this file
|
||||||
|
# main2.cpp # Build it (it doesnt have a main() function, but maybe it includes it)
|
||||||
|
|
||||||
|
[hooks]
|
||||||
|
# These are defined equal to [dependencies],files names matching bii*stage*hook.py
|
||||||
|
# will be launched as python scripts at stage = {post_process, clean}
|
||||||
|
# CMakeLists.txt + bii/my_post_process1_hook.py bii_clean_hook.py
|
||||||
|
|
||||||
|
[includes]
|
||||||
|
# Mapping of include patterns to external blocks
|
||||||
|
# hello*.h: user3/depblock # includes will be processed as user3/depblock/hello*.h
|
||||||
|
|
||||||
|
[data]
|
||||||
|
# Manually define data files dependencies, that will be copied to bin for execution
|
||||||
|
# By default they are copied to bin/user/block/... which should be taken into account
|
||||||
|
# when loading from disk such data
|
||||||
|
# image.cpp + image.jpg # code should write open("user/block/image.jpg")
|
||||||
|
|
17
macros.h
Normal file
17
macros.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_CPP_UTILS_MACROS_H_
|
||||||
|
#define MESSMER_CPP_UTILS_MACROS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disallow the copy and assignment constructors of a class
|
||||||
|
*/
|
||||||
|
#define DISALLOW_COPY_AND_ASSIGN(Class) \
|
||||||
|
Class(const Class &rhs) = delete; \
|
||||||
|
Class &operator=(const Class &rhs) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare a function parameter as intentionally unused to get rid of the compiler warning
|
||||||
|
*/
|
||||||
|
#define UNUSED(expr) (void)(expr)
|
||||||
|
|
||||||
|
#endif
|
43
optional_ownership_ptr.h
Normal file
43
optional_ownership_ptr.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_CPP_UTILS_OPTIONALOWNERSHIPPOINTER_H_
|
||||||
|
#define MESSMER_CPP_UTILS_OPTIONALOWNERSHIPPOINTER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* optional_ownership_ptr can be used to hold a pointer to an instance of an object.
|
||||||
|
* The pointer might or might not have ownership of the object.
|
||||||
|
*
|
||||||
|
* If it has ownership, it will delete the stored object in its destructor.
|
||||||
|
* If it doesn't have ownership, it won't.
|
||||||
|
*
|
||||||
|
* You can create such pointers with
|
||||||
|
* - WithOwnership(ptr)
|
||||||
|
* - WithoutOwnership(ptr)
|
||||||
|
* - null()
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace cpputils {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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);});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
optional_ownership_ptr<T> WithoutOwnership(T *obj) {
|
||||||
|
return optional_ownership_ptr<T>(obj, [](T*){});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
optional_ownership_ptr<T> null() {
|
||||||
|
return WithoutOwnership<T>(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
24
pointer.h
Normal file
24
pointer.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef MESSMER_CPP_UTILS_POINTER_H_
|
||||||
|
#define MESSMER_CPP_UTILS_POINTER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace cpputils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dynamic_cast implementation for unique_ptr (moving unique_ptr into a unique_ptr of different type)
|
||||||
|
*/
|
||||||
|
template<typename DST, typename SRC>
|
||||||
|
inline std::unique_ptr<DST> dynamic_pointer_move(std::unique_ptr<SRC> &source) {
|
||||||
|
//TODO Deleter
|
||||||
|
DST *casted = dynamic_cast<DST*>(source.get());
|
||||||
|
if (casted != nullptr) {
|
||||||
|
source.release();
|
||||||
|
}
|
||||||
|
return std::unique_ptr<DST>(casted);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
6
test/main.cpp
Normal file
6
test/main.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "google/gtest/gtest.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
112
test/optional_ownership_ptr_test.cpp
Normal file
112
test/optional_ownership_ptr_test.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#include "google/gtest/gtest.h"
|
||||||
|
#include "../OptionalOwnershipPointer.h"
|
||||||
|
|
||||||
|
using namespace fspp;
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::function;
|
||||||
|
using ::testing::Test;
|
||||||
|
using fspp::ptr::optional_ownership_ptr;
|
||||||
|
|
||||||
|
#define UNUSED(x) ((void)x)
|
||||||
|
|
||||||
|
class TestObject {
|
||||||
|
public:
|
||||||
|
TestObject(function<void()> destructorListener) : _destructorListener(destructorListener) {}
|
||||||
|
virtual ~TestObject() {
|
||||||
|
_destructorListener();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
function<void()> _destructorListener;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestObjectHolder {
|
||||||
|
public:
|
||||||
|
TestObjectHolder()
|
||||||
|
: _isDestructed(false),
|
||||||
|
_testObject(new TestObject([this]() {_isDestructed = true;})) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~TestObjectHolder() {
|
||||||
|
if (!_isDestructed) {
|
||||||
|
delete _testObject;
|
||||||
|
_isDestructed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestObject *get() {
|
||||||
|
return _testObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDestructed() {
|
||||||
|
return _isDestructed;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool _isDestructed;
|
||||||
|
TestObject *_testObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionalOwnershipPointerTest: public Test {
|
||||||
|
public:
|
||||||
|
TestObjectHolder obj;
|
||||||
|
TestObjectHolder obj2;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, TestIsInitializedCorrectly) {
|
||||||
|
EXPECT_FALSE(obj.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnership) {
|
||||||
|
{
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithOwnership(unique_ptr<TestObject>(obj.get()));
|
||||||
|
UNUSED(ptr);
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(obj.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DestructsWhenItHasOwnershipAfterAssignment) {
|
||||||
|
{
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithoutOwnership(obj.get());
|
||||||
|
ptr = fspp::ptr::WithOwnership(unique_ptr<TestObject>(obj2.get()));
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(obj.isDestructed());
|
||||||
|
EXPECT_TRUE(obj2.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DoesntDestructWhenItDoesntHaveOwnership) {
|
||||||
|
{
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithoutOwnership(obj.get());
|
||||||
|
UNUSED(ptr);
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(obj.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DoesntDestructWhenItDoesntHaveOwnershipAfterAssignment) {
|
||||||
|
{
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithOwnership(unique_ptr<TestObject>(obj.get()));
|
||||||
|
ptr = fspp::ptr::WithoutOwnership(obj2.get());
|
||||||
|
EXPECT_TRUE(obj.isDestructed());
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(obj2.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DestructsOnReassignmentWithNull) {
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithOwnership(unique_ptr<TestObject>(obj.get()));
|
||||||
|
ptr = fspp::ptr::null<TestObject>();
|
||||||
|
EXPECT_TRUE(obj.isDestructed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptr1) {
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::null<TestObject>();
|
||||||
|
UNUSED(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptrWithoutOwnership) {
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithoutOwnership((TestObject*)nullptr);
|
||||||
|
UNUSED(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OptionalOwnershipPointerTest, DoesntCrashWhenDestructingNullptrWithOwnership) {
|
||||||
|
optional_ownership_ptr<TestObject> ptr = fspp::ptr::WithOwnership(unique_ptr<TestObject>(nullptr));
|
||||||
|
UNUSED(ptr);
|
||||||
|
}
|
67
test/pointer_test.cpp
Normal file
67
test/pointer_test.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#include "google/gtest/gtest.h"
|
||||||
|
#include "../pointer.h"
|
||||||
|
|
||||||
|
using namespace fspp;
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
class Parent {
|
||||||
|
public:
|
||||||
|
virtual ~Parent() {}
|
||||||
|
};
|
||||||
|
class Child: public Parent {};
|
||||||
|
class Child2: public Parent {};
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, NullPtrParentToChildCast) {
|
||||||
|
unique_ptr<Parent> source(nullptr);
|
||||||
|
unique_ptr<Child> casted = dynamic_pointer_move<Child>(source);
|
||||||
|
EXPECT_EQ(nullptr, source.get());
|
||||||
|
EXPECT_EQ(nullptr, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, NullPtrChildToParentCast) {
|
||||||
|
unique_ptr<Child> source(nullptr);
|
||||||
|
unique_ptr<Parent> casted = dynamic_pointer_move<Parent>(source);
|
||||||
|
EXPECT_EQ(nullptr, source.get());
|
||||||
|
EXPECT_EQ(nullptr, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, NullPtrSelfCast) {
|
||||||
|
unique_ptr<Parent> source(nullptr);
|
||||||
|
unique_ptr<Parent> casted = dynamic_pointer_move<Parent>(source);
|
||||||
|
EXPECT_EQ(nullptr, source.get());
|
||||||
|
EXPECT_EQ(nullptr, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, ValidParentToChildCast) {
|
||||||
|
Child *obj = new Child();
|
||||||
|
unique_ptr<Parent> source(obj);
|
||||||
|
unique_ptr<Child> casted = dynamic_pointer_move<Child>(source);
|
||||||
|
EXPECT_EQ(nullptr, source.get()); // source lost ownership
|
||||||
|
EXPECT_EQ(obj, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, InvalidParentToChildCast1) {
|
||||||
|
Parent *obj = new Parent();
|
||||||
|
unique_ptr<Parent> source(obj);
|
||||||
|
unique_ptr<Child> casted = dynamic_pointer_move<Child>(source);
|
||||||
|
EXPECT_EQ(obj, source.get()); // source still has ownership
|
||||||
|
EXPECT_EQ(nullptr, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, InvalidParentToChildCast2) {
|
||||||
|
Child2 *obj = new Child2();
|
||||||
|
unique_ptr<Parent> source(obj);
|
||||||
|
unique_ptr<Child> casted = dynamic_pointer_move<Child>(source);
|
||||||
|
EXPECT_EQ(obj, source.get()); // source still has ownership
|
||||||
|
EXPECT_EQ(nullptr, casted.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(DynamicPointerMoveTest, ChildToParentCast) {
|
||||||
|
Child *obj = new Child();
|
||||||
|
unique_ptr<Child> source(obj);
|
||||||
|
unique_ptr<Parent> casted = dynamic_pointer_move<Parent>(source);
|
||||||
|
EXPECT_EQ(nullptr, source.get()); // source lost ownership
|
||||||
|
EXPECT_EQ(obj, casted.get());
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user