Skip to content

Commit

Permalink
conan.io support
Browse files Browse the repository at this point in the history
This commit adds a conan.io package recipe using my testing channel
(Manu343726/testing). The package will be manually released into my
own conan repository in artifactory
(https://bintray.com/manu343726/conan-packages). Note debug_assert is
released there too.

The package is tagged with version 0.1, until an official release of
type_safe is done.

The package currently depends on debug_assert 1.3, the latest release
packaged.

No automatic conan packaging is implemented in the CI, only a package
test. Note this must be trivial (encrypting the artifactory user key in
travis, using one of the travis environment variables to check if we're
building a release, etc).
  • Loading branch information
Manu343726 committed Jan 3, 2018
1 parent 0320c2e commit fa24512
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 1 deletion.
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
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,16 @@ install:
- $CXX --version
- $CMAKE --version

- pip install --user conan && export PATH=$PATH:$HOME/.local/bin

- cd type_safe/

script:
- mkdir build/ && cd build/
- $CMAKE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_CXX_FLAGS="-Werror -pedantic -Wall -Wextra -Wconversion -Wsign-conversion -Wno-parentheses" -DTYPE_SAFE_BUILD_TEST_EXAMPLE=ON -DTYPE_SAFE_BUILD_DOC="$BUILD_DOCS" -DTYPE_SAFE_STANDARDESE_DOWNLOAD_DIRECTORY=../../standardese/ ../
- $CMAKE --build .
- ./test/type_safe_test
- cd .. && conan create Manu343726/testing --build=outdated && cd build

after_success:
- git config --global user.name "Travis CI"
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 [ ![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)

[![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)
[![badge](https://img.shields.io/badge/conan.io-type_safe%2F0.1-green.svg?logo=data:image/png;base64%2CiVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAA1VBMVEUAAABhlctjlstkl8tlmMtlmMxlmcxmmcxnmsxpnMxpnM1qnc1sn85voM91oM11oc1xotB2oc56pNF6pNJ2ptJ8ptJ8ptN9ptN8p9N5qNJ9p9N9p9R8qtOBqdSAqtOAqtR%2BrNSCrNJ/rdWDrNWCsNWCsNaJs9eLs9iRvNuVvdyVv9yXwd2Zwt6axN6dxt%2Bfx%2BChyeGiyuGjyuCjyuGly%2BGlzOKmzOGozuKoz%2BKqz%2BOq0OOv1OWw1OWw1eWx1eWy1uay1%2Baz1%2Baz1%2Bez2Oe02Oe12ee22ujUGwH3AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBQkREyOxFIh/AAAAiklEQVQI12NgAAMbOwY4sLZ2NtQ1coVKWNvoc/Eq8XDr2wB5Ig62ekza9vaOqpK2TpoMzOxaFtwqZua2Bm4makIM7OzMAjoaCqYuxooSUqJALjs7o4yVpbowvzSUy87KqSwmxQfnsrPISyFzWeWAXCkpMaBVIC4bmCsOdgiUKwh3JojLgAQ4ZCE0AMm2D29tZwe6AAAAAElFTkSuQmCC)](http://www.conan.io/source/type_safe/0.1/Manu343726/testing)

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

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

class TypeSafe(ConanFile):
name = 'type_safe'
url = 'https://foonathan.github.io/blog/2016/10/11/type-safe.html'
version = '0.1'
username = 'Manu343726'
channel = 'testing'
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 fa24512

Please sign in to comment.