Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

conan.io support #30

Merged
merged 8 commits into from
Feb 1, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ignore conan.io package test buildtree
test_package/build
22 changes: 15 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,44 @@ matrix:
apt:
sources: ['ubuntu-toolchain-r-test', 'boost-latest']
packages: ['g++-5', 'libboost1.55-all-dev']
env: TOOLSET=clang++ BUILD_TYPE='Release' BUILD_DOCS=1
env: TOOLSET=clang++ TOOLSET_C=clang BUILD_TYPE='Release' BUILD_DOCS=1

- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8']
env: TOOLSET=g++-4.8 BUILD_TYPE='Debug' BUILD_DOCS=0
env: TOOLSET=g++-4.8 TOOLSET_C=gcc-4.8 BUILD_TYPE='Debug' BUILD_DOCS=0
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.8']
env: TOOLSET=g++-4.8 BUILD_TYPE='Release' BUILD_DOCS=0
env: TOOLSET=g++-4.8 TOOLSET_C=gcc-4.8 BUILD_TYPE='Release' BUILD_DOCS=0

- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: TOOLSET=g++-5 BUILD_TYPE='Debug' BUILD_DOCS=0
env: TOOLSET=g++-5 TOOLSET_C=gcc-5 BUILD_TYPE='Debug' BUILD_DOCS=0
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5']
env: TOOLSET=g++-5 BUILD_TYPE='Release' BUILD_DOCS=0
env: TOOLSET=g++-5 TOOLSET_C=gcc-5 BUILD_TYPE='Release' BUILD_DOCS=0

- os: osx
compiler: clang
env: TOOLSET=clang++ BUILD_TYPE='Debug' BUILD_DOCS=0
env: TOOLSET=clang++ TOOLSET_C=clang BUILD_TYPE='Debug' BUILD_DOCS=0
- os: osx
compiler: clang
env: TOOLSET=clang++ BUILD_TYPE='Release' BUILD_DOCS=0
env: TOOLSET=clang++ TOOLSET_C=clang BUILD_TYPE='Release' BUILD_DOCS=0

install:
- cd ../
Expand All @@ -63,9 +63,13 @@ install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CMAKE=$TRAVIS_BUILD_DIR/../cmake-3.3.0-Darwin-x86_64/CMake.app/Contents/bin/cmake; fi

- export CXX=$TOOLSET
- export CC=$TOOLSET_C
- $CXX --version
- $CC --version
- $CMAKE --version

- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then pip install --user conan && export PATH=$PATH:$HOME/.local/bin; fi

- cd type_safe/

script:
Expand All @@ -74,6 +78,10 @@ script:
- $CMAKE --build .
- ./test/type_safe_test

# Run conan package test (only on linux, pip is not available in the osx build)
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then conan remote add Manu343726 https://api.bintray.com/conan/manu343726/conan-packages; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cd .. && conan create . Manu343726/testing --build=outdated && cd build; fi

after_success:
- git config --global user.name "Travis CI"
- git config --global user.email "[email protected]"
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# type_safe
# type_safe

[![Build Status](https://travis-ci.org/foonathan/type_safe.svg?branch=master)](https://travis-ci.org/foonathan/type_safe)
[![Build status](https://ci.appveyor.com/api/projects/status/aw1j2h2s52g4laen/branch/master?svg=true)](https://ci.appveyor.com/project/foonathan/type-safe/branch/master)
[ ![Download](https://api.bintray.com/packages/manu343726/conan-packages/type_safe%3AManu343726/images/download.svg) ](https://bintray.com/manu343726/conan-packages/type_safe%3AManu343726/_latestVersion)

type_safe provides zero overhead abstractions that use the C++ type system to prevent bugs.

Expand Down
23 changes: 23 additions & 0 deletions conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from conans import ConanFile
from conans.tools import download, untargz
import os

class TypeSafe(ConanFile):
name = 'type_safe'
url = 'https://github.com/foonathan/type_safe'
version = '0.1'
requires = 'debug_assert/1.3@Manu343726/testing'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing I have to update this one everytime I release a new version and/or update debug_assert?

exports = '*.hpp'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use exports_sources instead

generators = 'cmake'


def source(self):
tar = 'type_safe-{}.tar.gz'.format(self.version)
url = 'https://github.com/foonathan/type_safe/archive/v{}.tar.gz'.format(self.version)
download(url, tar)
untargz(tar)

def package(self):
includedir = os.path.join('include', 'type_safe')
srcdir = os.path.join('type_safe-{}'.format(self.version), includedir)
self.copy('*.hpp', src=srcdir, dst=includedir)
12 changes: 12 additions & 0 deletions test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
project(type_safe_test_package)
cmake_minimum_required(VERSION 2.8)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_executable(example example.cpp)
if(NOT MSVC)
target_compile_options(example PRIVATE -std=c++11)
endif()

target_link_libraries(example PRIVATE ${CONAN_TARGETS})
14 changes: 14 additions & 0 deletions test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from conans import ConanFile, CMake
import os

class TypeSafe(ConanFile):
settings = 'os', 'compiler', 'build_type', 'arch'
generators = 'cmake'

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
self.run(os.path.join('.', 'bin', 'example'))
130 changes: 130 additions & 0 deletions test_package/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (C) 2016 Jonathan Müller <[email protected]>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#include <cctype>
#include <iostream>
#include <string>

#include <type_safe/optional.hpp>
#include <type_safe/optional_ref.hpp>
#include <type_safe/visitor.hpp>

namespace ts = type_safe;

// type safe back function
// impossible to forget precondition
ts::optional<char> back(const std::string& str)
{
return str.empty() ? ts::nullopt : ts::make_optional(str.back());
}

// some imaginary lookup function
ts::optional<int> lookup(char c)
{
// simulate lookup
return c == 'T' ? ts::nullopt : ts::make_optional(c + 1);
}

// task: get last character of string,
// convert it to upper case
// look it up
// and return the integer or 0 if there is no integer

// this is how'd you do it with std::optional
int task_std(const std::string& str)
{
auto c = back(str);
if (!c)
return 0;
auto upper_case = std::toupper(c.value());
auto result = lookup(upper_case);
return result.value_or(0);
}

// this is how'd you do it with the monadic functionality
// there is no need for branches and no errors possible
// it generates identical assembler code
int task_monadic(const std::string& str)
{
return back(str)
// map takes a functor and applies it to the stored value, if there is any
// the result is another optional with possibly different type
.map([](char c) -> char { return std::toupper(c); })
// lookup is similar to map
// but the result of map(lookup) would be a ts::optional<ts::optional<int>>
// bind() calls unwrap() to flatten it to ts::optional<int>
.bind(lookup)
// value_or() as usual
.value_or(0);
}

// a visitor for an optional
// this again makes branches unnecessary
struct visitor
{
template <typename T>
void operator()(const T& val)
{
std::cout << val << '\n';
}

void operator()(ts::nullopt_t)
{
std::cout << "nothing :(\n";
}
};

int main()
{
std::cout << task_std("Hello World") << ' ' << task_monadic("Hello World") << '\n';
std::cout << task_std("Hallo Welt") << ' ' << task_monadic("Hallo Welt") << '\n';
std::cout << task_std("") << ' ' << task_monadic("") << '\n';

// visit an optional
ts::optional<int> opt(45);
ts::visit(visitor{}, opt);
opt.reset();
ts::visit(visitor{}, opt);

// savely manipulate the value if there is one
// with() is an inplace map()
// and thus more efficient if you do not need to change the type
ts::with(opt, [](int& i) {
std::cout << "got: " << i << '\n';
++i;
});

// an optional reference
// basically a pointer, but provides the funcionality of optional
ts::optional_ref<int> ref;

int a = 42;
ref = a; // assignment rebinds
std::cout << ref.value() << '\n';

ref.value() = 0;
std::cout << a << '\n';

int b = 5;
ref.value_or(b)++;
std::cout << a << ' ' << b << '\n';

ref = nullptr; // assign nullptr as additional way to reset

// an optional reference to const
ts::optional_ref<const int> ref_const(ref);

// create optional_ref from pointer
auto ptr = ts::ref(&a);
auto ptr_const = ts::cref(&a);

// map() takes a functor and wraps the result in an optional itself
// transform() does not wrap it in an optional to allow arbitrary transformation
// but it needs a fallback value if there is no value stored
// here transform() is used to transform an optional_ref to a normal optional
auto ptr_transformed = ptr.transform(ts::optional<int>(), [](int a) { return a; });
// note that the same for this particular situation can be achieved like this
ptr_transformed = ts::copy(ptr); // there is also ts::move() to move the value
std::cout << ptr_transformed.value() << '\n';
}