Skip to content

Commit

Permalink
conan.io support (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
Manu343726 authored and foonathan committed Feb 1, 2018
1 parent 132167c commit 96662e1
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 8 deletions.
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'
exports = '*.hpp'
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';
}

0 comments on commit 96662e1

Please sign in to comment.