Coder Social home page Coder Social logo

mnmlstc / core Goto Github PK

View Code? Open in Web Editor NEW
245.0 29.0 33.0 1.36 MB

C++14 (and beyond) library features implemented in C++11

Home Page: https://mnmlstc.github.io/core/

License: Other

C++ 96.74% CMake 2.39% Python 0.61% Shell 0.25%
c-plus-plus-11 c-plus-plus-14 c-plus-plus cxx

core's Introduction

Overview

MNMLSTC Core is a small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions, or some proposals that have not been completely approved yet.

Information on installing and using MNMLSTC Core can be found in its documentation.

MNMLSTC Core is released under the Apache 2.0 License. Build scripts provided by MNMLSTC Core are released under the CC0 1.0 Universal License.

image

image

Components

Some components provided by MNMLSTC Core are:

  • variant<Ts...>
  • optional<T>
  • expected<T>
  • deep_ptr<T>
  • poly_ptr<T>
  • string_view
  • range<T>
  • any

Details on each component can be found in MNMLSTC Core's documentation. All of the MNMLSTC Core components reside in the core namespace. The library is organized equivalent to the standard library e.g., components related to memory are in the memory header, functional components in the functional header, etc.

Requirements

There are several requirements to fully use MNMLSTC Core:

  • A C++11 compliant compiler (GCC 4.8.1 or Clang 3.4 meet the minimum feature set required to build and use MNMLSTC Core)
  • CMake 3.0.0

Additionally, to develop or package MNMLSTC Core, the following are required:

Sphinx and the Guzzle Sphinx Theme are only necessary if generating documentation manually to be included with the package.

WiX Toolset is only required if building packages for Windows.

core's People

Contributors

bruxisma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

core's Issues

variant get() function

It would be nice to have 'get' as member function of the variant template, instead of using core::get(...). If I understood the documentation for 'auto get() noexcept' correctly, it implies that is should actually be a member function:

Depending on the value of *this (reference, const reference, rvalue) the type of the value returned will be affected as well.

std::string comparison with string_view

#include <core/string.hpp>

int main() {
    const std::string a = "a";
    const std::string b = "b";
    core::string_view bv{b};

    return a == bv;
}

This fails to compile because:

compare.cc:8:14: error: no match for ‘operator==’ (operand types are ‘const string {aka const std::basic_string<char>}’ and ‘core::v1::string_view {aka core::v1::basic_string_view<char>}’)

It works with boost string_ref http://www.boost.org/doc/libs/1_55_0/libs/utility/doc/html/string_ref.html

string_view::max_size() is doesn't match the standard (revision 7)

I was unable to find a revision of the string_view proposal past revision 7, but the text for max_size in rev 7 is as follows:

constexpr size_type max_size() const noexcept
Returns: The largest possible number of char-like objects that can be referred to by a basic_string_view.

This implementation currently only returns the size of the current string view which is different from the standard library implementation provided on my machine (Apple LLVM version 7.0.2 (clang-700.1.81)).

I believe it should return ::std::numeric_limits::<size_type>::max() instead.

Place all optional types within the optional component

As of release 1.0, MNMLSTC Core had 2 optional types, core::optional<T> and core::expected<T>. With 1.1 MNMLSTC Core will gain a third optional type, core::result<T> (mentioned in issue #13). It is most likely a good idea to move both expected<T> and result<T> into the optional component. This would make the in_place_t type available, allowing for all optional types to be constructed with a variadic number of arguments.

This will break the semantic versioning, however hopefully no one has tried to actually use the expected<T> for a very critical app yet, because it is woefully lacking in features when compared to core::optional<T>.

string_view::find* functions do not take a position

Revision 7 of the string_view proposal shows all the find* functions taking a position. Currently, core::string_view does not do this, and it limits the interoperability with std::string (as string_view is intended to be a drop-in API replacement for a std::string const&)

Implementing these functions is necessary for compatibility with the proposal. HOWEVER, these functions cannot be constexpr due to limitations with C++11. As MNMLSTC Core does focus on targeting C++11, we have no way of implementing these where the non-constexpr case would be easily optimizable.

While there is a plan to eventually have a version of MNMLSTC Core targeting C++14 (MNMLSTC Core 2.0), that it outside the scope of the 1.2 release.

Add either<T, U>

With the boost proposal of an expected<T, U> it would make sense to make an either<T, U> that performs the same functionality that it would in other languages. The reason for this over using a variant as an alias is:

  • either<T, U> would be a smaller type (no integer to tell which is which)
  • Would be constexpr in C++11 terms
  • result<T> and expected<T> could be turned into template aliases (in a future major release. This can't be done now, as this would break compatibility, which would in turn break the promise of semantic versioning. It's happened only once before (moving the expected<T> into the core/optional.hpp header) and I would prefer to not do it again.

Additionally, naming a type that is either A or B expected<T, U> is probably not the best idea. Honestly one would expect either T or U. Not expect either T or U.

Add match function for all optional types

As optional types are effectively variants (pedantically speaking they're not, but they are, but they're not), there is no reason why a match function for all optional types should not be provided. This should be both a member function, as well as an ADL-capable function within the core::v1 namespace. This would allow for stuff like:

optional<int> f { 4 };
f.match(
  [] (int x) { /* do something here */ },
  [] (nullopt_t) { /* do something else here */ }
);

Implement sigslot proposal

This would be a big add, but there's some good reasons why it's worth the effort

  • Signals and slots are wonderful
  • Boost sigslot is powerful but bogged down with complicated and heavy features like "slot groups"
  • sigslot's source code is a mess with idioms to keep it compatible with older versions of C++, a modern implementation would be way easier to people to reason about and less complications mean less bugs
  • Most implementations throw linked-lists at the problem which are terrible for iterating over, which is the one thing signals are supposed to do well and fast!

What's specified in the proposal looks quite doable. Maybe a version 2 feature?

Sidenote: It'd be extra cool if it didn't rely on as many heap allocations as boost (it creates a shared_ptr for each entry!). It might also be possible to avoid using a linked-list or at least optimize for the common case of only 1-2 handlers per signal. Signals almost always are fired far more often than slots are connected/disconnected and linked-lists do unspeakable things to your CPU's cache when you try and iterate through them. Chromium actually uses a plain old vector and assigns each connection a unique id. You have to brute force find/remove in order to disconnect signals but this is often still faster than using a linked list.

Let me know what you think! I'd be willing to create a prototype over the weekend if you're interested.

Please add VS 2015 support if possible

We are using MNMLSTC core to provide polyfills for string_view and optional in the upcoming MongoDB C++11 driver: https://github.com/mongodb/mongo-cxx-driver/tree/master

It has been a big help for our GCC and clang builds, but unfortunately core doesn't appear to work on VS 2015. I just tried HEAD of master last night. If we can't use MNMLSTC core with VS 2015, then our options are to either build our own polyfills from scratch and use those everywhere, which we are not excited about, or to find a different source of the polyfills to use only with VS 2015, which we also aren't too excited about.

It does look like some CMake awareness of WIN32 was added recently. Is VS 2015 support on the roadmap for 2.0? I realize that VS 2015 is still a pretty flawed C++11 compiler, so perhaps it just isn't viable yet for something like core.

In any event, an answer either way would be helpful, and excited to see work progressing towards core 2.0.

Clean up header dependency

The header dependency route in MNMLSTC Core is a bit unclean at the moment. For instance, the utility component does not include the type traits component, even though it would greatly benefit from it. A small pass to clean up these headers is required. While I originally was against all components of MNMSLTC Core depending on the type traits component, it seems as though this is inevitable due to how useful it is.

Compile error when constructing any with const T* (clang / Mac OS X)

Hello Izzy!! :D

core::v2::any issues a compiler error when the constructor for a parameter of constant pointer type is used. This can be reproduced by attempting to wrap a pointer to a const int:

const int x = 5;
core::v2::any container(&x);

reinterpret_cast from 'core::v2::impl::data_type*' (aka void**) to 'core::v2::impl::dispatch<const MyType*, true>' (aka const MyType**) casts away qualifiers.

I'm using Clang on a slightly outdated Xcode and using this library to aid in compatibility with old versions of Mac OS X.

Add unsafe_any_cast for any component

unsafe_any_cast is considered to be a much faster use of any_cast and some arguments have been given that it should be in the Library Fundamentals TS. Additionally, both Boost.Any and the Adobe any implementation provide an unsafe_any_cast.

While I am definitely against the introduction of potential undefined behavior (which is more than possible with unsafe_any_cast), the potential performance benefits as well as interop with other any implementations is more than worth it.

Add constexpr forward and move

In order to resolve Issue #1, a constexpr forward and move equivalent are necessary. Additionally, internals of MNMLSTC Core should rely on these functions.

Future releases?

Hi, are there any future releases planned? For our case, it'd be nice to have the fix to #23 without building from master.

Thank you!
Kevin

Hash of *std::*string_view must equal hash of corresponding std::string object

std::hash<std::string_view> on cppreference

Section 24.4.5 in C++ 17 working draft N4659: Hash support:

Note: The hash value of a string view object is equal to the hash value of the corresponding string object.

Currently the following tests fail and although it's not std::string_view, you might consider this for core::string_view.

  SECTION("hash-std::string") {
      CHECK( std::hash<core::string_view>()("hello") == std::hash<std::string>()("hello") );
      CHECK( std::hash<core::string_view>()("world") == std::hash<std::string>()("world") );
  }
prompt> test-string-view.exe --reporter compact
string-view.cpp:383: failed: std::hash<core::string_view>()("hello") == std::hash<std::string>()("hello") for: 2191231550387646743 == 2762169579135187400
string-view.cpp:384: failed: std::hash<core::string_view>()("world") == std::hash<std::string>()("world") for: 5568329560871645431 == 8751027807033337960
Failed 1 test case, failed 2 assertions.

Namespace scope pass required

There are many parts of MNMLSTC Core that currently resolve to using the standard namespace without a full global resolution before hand (that is, std:: is used instead of ::std::. It is considered good practice to fully resolve the standard library's namespace, and a pass to insure this should be done on all MNMLSTC Core components.

Deprecate usage of MNMLSTC Unittest and replace it with the Catch Framework.

MNMLSTC Unittest was an experiment for unit testing libraries. It wasn't widely used outside of MNMLSTC libraries, and it is time to say farewell. If C++17 (or some technical specification) adds a way to pass the current line and file of an exception without the use of macros, MNMLSTC Unittest may move out of deprecation. However, until that time, MNMLSTC Core should use the Catch, due to its popularity and small size.

Additionally, the tests/CMakeLists.txt file should handle the downloading and configuring of Catch for unit tests, should they be enabled. This will remove the requirement of having a unit test library installed on the machine, and simply require that an internet connection be available.

Author's Note:

I wrote MNMLSTC Unittest to see if it would be possible to have a unit test library in the style of
Python, and while it more or less worked, I unfortunately have to admit that having line numbers and
files in debug output is extremely useful in large projects. MNMLSTC Unittest was fun to write, but I
feel that Catch will make it easier for others to be involved and test changes or fixes to MNMLSTC
Core (and other MNMLSTC Libraries). I will admit that it was a good run, but there are a large
number of frankly superior unit test libraries that are able to interact with tools like Jenkins and
Hudson (or anything that reads JUnit XML). Additionally, MNMLSTC Unittest never played well with
CDash, despite relying entirely on CTest as its test runner. With all of the above issues stated, it was
only a matter of time until MNMLSTC Unittest was deprecated.

core::basic_string_view constness and substring

Dear Tres,

I found no other way to contacting you, so first of all: thanks for that wonderful library. Lightweight, small, no boost'ish depencies, and modern c++11 (sometimes too modern since we stick with gcc 4.7.3+ versions), but some of it still is working and extremly helpful in my daily business.

What I wanted to ask: current, string_view is a read-only type. Do you plan to make it mutable, so immutability would be decided on the constness of the instance (remark: I have used pj_str_t of pjsip.org for years, which is basically the same as the string_view, but mutable)?

Maybe the application is overlapping to the range concept, but modifying a string_view's underlying data would be a nice feature, hiding away the underlaying/owning data structure.

A second remark regarding string_view::find()

the std::basic_string exposes a

  size_type
  find(_CharT __c, size_type __pos = 0) const _GLIBCXX_NOEXCEPT;

whereas the string_view is basically missing the offset parameter __pos. Any plans to get compatible with this one?

BTW: what are you working on in 'real'-life? For PM: puls (at) x-fabric (single dot) com

Thanks and have a good day,
Roman

PS: we tried working with the variant class, but in practice, a single callstack in gdb can fill multiple screens with that approach. Maybe a .gdb printer may help here.

Bring expected<T> up to par with optional<T>

This is partially dependent on #14. The expected<T> optional type is missing an extremely large feature set when compared to optional<T>. It needs to have a variety of functions added (emplace, variadic constructors), as well as additional relational operator overloads.

Maybe a kitchen sink, while I'm at it.

default constructible requirement for result<T>::value_type?

Hi,

When i try to instantiate core::result<T> on types which are not default constructible, i run into a compiler error. As far as i see this requirement is not listed in the documentation. Looking at the source code, i find this:

  result (::std::error_condition const& ec) :
    valid { not ec }
  {
    if (*this) { ::new (::core::as_void(this->val)) value_type(); }
    else { ::new (::core::as_void(this->cnd)) error_type(ec); }
  }

So if someone uses an 'ok' error_condition in the result the underlying storage will be initialized with a default constructed instance of T. I see the underlying intent that since there is no error thus there should be a value, but this is also adding the default constructible requirement for type T, which i see a bit restrictive. Is there something that could be done, to use non default constructible types?

Thanks
Andras

Make invoke function constexpr

Now that #1 has been closed, and a constexpr move and forward function were added to the utility component, the core::invoke function and its overloads can be set to be constexpr.

The only limitation is that the unpack versions of core::invoke will not be constexpr, due to limitations with std::get, std::tuple, friends.

Add <numeric> functions that take a range

Boost.Range provides several functions to simplify the C++ stdlib's <numeric> functions.

There is no reason that MNLSTC Core cannot provide this same feature set.

Add result<T> type.

This type is partially inspired by rust-lang's Result<T, E>. Unlike rust-lang, however, result<T> will be much like expected<T>, except (heh) instead of an exception it will contain a std::error_condition. This will allow for user defined conditions while also remaining portable.

It will have an interface equivalent to expected<T>, minus exception related tasks. It follows in the footsteps of optional<T>, for which no error is expressed. It is also safer to use for platforms where exceptions may not be entirely viable, such as the Playstation 4. An exception may be thrown in result<T>::value where there is no value to use, however. (It will always be of type std::system_error).

implicit conversion from pointer to observer_ptr

This is a nice (and I believe completely safe) convenience:

#include <core/memory.hpp>

core::observer_ptr<int> foo(int *i) {                                                                                                                                                                                                                                                                                                                                       
    return i;
}

int main() {
    int a = 0;
    auto b = foo(&a);
}

but it currently fails:

ptr.cc: In function ‘core::v1::observer_ptr<int> foo(int*)’:
ptr.cc:4:12: error: could not convert ‘i’ from ‘int*’ to ‘core::v1::observer_ptr<int>’
     return i;

Add missing type traits

There are quite a few type traits in the standard that are missing here. Here's a reference implementation I've been using in personal projects (pretty much copy and pasted from the standard proposal)

I was going to submit a pull request with these added but I notice you've implemented your own versions of common_type and a few other traits. Is there a reason for this? Both libc++ and libstd++ support it

Add is_swappable and is_nothrow_swappable type traits

In reference to Issue #7, it will be easier to mark many swap function as noexcept if these type traits are available. While clang does provide some of their own traits, these will not depend on compiler or library specific implementations.

Exception safety with allocators in any

static void clone (data_type const& source, data_type& data) {
    allocator_type alloc { };
    auto const& value = *static_cast<Type* const>(source);
    auto pointer = allocator_traits::allocate(alloc, 1);
    allocator_traits::construct(alloc, pointer, value);
    data = pointer;
  }

If the construction throws, the allocated memory is leaked. The best way (I've seen) to work around this issues is to store the allocated memory in a unique_ptr with a custom dtor that simply calls allocator::deallocate.

For reference here is how I solved this problem in my any implementation (Which is based off of libc++'s std::function).

storage_base* copy() const
{
    using NewAlloc = typename Alloc::template rebind<storage_type>::other;
    NewAlloc a(m_pair.second());
    using Dtor = allocator_destructor<NewAlloc>;
    std::unique_ptr<storage_type, Dtor> tmp(a.allocate(1), Dtor(a, 1));
    ::new ((void*)tmp.get()) storage_type(
        m_pair.first(), Alloc(a)
        );
    return tmp.release();
}

GCC 5 -Wall issues warning about clang::fallthrough attribute placement in string_view header

When building libbsoncxx against core HEAD with -Wall, I'm getting lots of warnings about the use of the clang::fallthrough attribute in the new string_view header:

src/bsoncxx/third_party/EP_mnmlstc_core-prefix/src/EP_mnmlstc_core/include/core/string_view.hpp:100:55: warning: attributes at the beginning of statement are ignored [-Wattributes]
       case 2: hash ^= ::std::uint64_t(data[1]) << 8;  [[clang::fallthrough]];

Easy enough to work around by adding -Wno-attribute but that is not ideal.

SEGV when using small types that are not noexcept copy constructable

Hello,

this is a bug in any / dispatch.

Types that are not noexcept copy constructable are treated by dispatch as not small, but their value is stored in the pointer of any like a small type. When applying any_cast to such an any instance a SEGV occurs as the value is interpreted as the address to the value.

Please see the following test case:

TEST_CASE("small-assignment", "[assignment]") {
  struct Foo {
    int f_;

    Foo()
        : f_(0) {
    }
    Foo(const Foo& other)
        : f_(other.f_) {
    }
    Foo(Foo&& other) {
      swap(*this, other);
    }

    Foo& operator=(Foo other) {
      swap(*this, other);
      return *this;
    }

    void swap(Foo& first, Foo& second) {
      if(&first != &second) {
        using std::swap;

        swap(first.f_, second.f_);
      }
    }
  };

  // not small because not noexcept
  CHECK_FALSE(::core::impl::is_small<Foo>::value);

  int f = 42;
  Foo foo;
  foo.f_ = f;

  CHECK(f == foo.f_);

  core::any a = foo;

  CHECK(f == foo.f_);
  CHECK(f == core::any_cast<Foo>(a).f_);  // Seg fault - the address (this) of
                                          // the temporary object has a value of
                                          // 0x2A (42)

  core::any b = a;

  CHECK(f == foo.f_);
  CHECK(f == core::any_cast<Foo>(a).f_);
  CHECK(f == core::any_cast<Foo>(b).f_);

  core::any c = std::move(a);

  CHECK(f == foo.f_);
  CHECK(0 == core::any_cast<Foo>(a).f_);
  CHECK(f == core::any_cast<Foo>(b).f_);
  CHECK(f == core::any_cast<Foo>(c).f_);
}

Add <algorithm> functions that take a range

Boost.Range provides a variety of functions that take a range type T, and then call the c++ stdlib <algorithm> header equivalent.

For example:

boost::for_each({1, 2, 3}, [](int x) { });

Will in turn call std::for_each. There is, honestly, no reason that MNMLSTC Core cannot provide this same functionality.

variant does not compile if first type is not default constructable

Compiling the following code with clang 3.4.2 using libc++ on Linux fails:

struct Test1
{
    Test1( int value ) {}
};
struct Test2
{
    Test2( double value ) {}
};
core::variant<Test1, Test2> test{ Test2{ 0.0 } };

error:

libs/modules/mnmlstc-core/git/include/core/type_traits.hpp:86:47: error: no type named 'type' in 'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename ::std::enable_if<B, T>::type;
                                              ^
libs/modules/mnmlstc-core/git/include/core/variant.hpp:221:11: note: in instantiation of template type alias 'enable_if_t' requested here
    class=enable_if_t<
          ^
test.hpp:141:29: note: in instantiation of template class 'core::v1::variant<Test1, Test2>' requested here
core::variant<Test1, Test2> test{ Test2{ 0.0 } };

Adding a default constructor to Test1 "fixes" the problem.

Add type based get for variant

core::variant<Ts...> does not currently support using a get function via a given type. This turns out to be easier to implement than one might think. As a result, there is no reason to NOT permit this kind of usage. Adding this feature will also give better interop with Boost.Variant.

core::function_traits<T>::argument<N> always return a type of the 1st argument

Test case:

#include <type_traits>
#include <core/functional.hpp>

struct A {};
struct B {};
struct C {};

typedef A(*foo)(B,C);

static_assert( std::is_same< core::function_traits<foo>::argument<0>, B >::value, "arg0 != B" );
static_assert( std::is_same< core::function_traits<foo>::argument<1>, C >::value, "arg1 != C" ); // fails

Tested on Apple clang-700.1.76 and Homebrew gcc 5.2.0 at OS X.

Add build time options to disable exceptions and RTTI

While some functions that would result in exceptions or usage of RTTI might not be called within a given project, a compiler will still attempt to generate code, and this can result in linker errors. There won't be a specific approach to detect whether or not a given compiler has exceptions enabled. Instead, the user will decide this during configuration, and use $<TARGET_PROPERTY:mnmlstc::core,INTERFACE_COMPILE_DEFINITIONS> in a given build. I'm still hesitant on adding a configure.hpp header.

Of course, this means that certain types will be unavailable in these situations (specifically, expected<T>)

Edit: 2015-JAN-30

The exceptions will be able to be disabled, however, RTTI is required for core::any to work. The definitions will be available at configure time, or can be added manually. This will be documented as well. If RTTI is disabled, including <core/any.hpp> will most likely result in the use of a #error. A single member function in core::variant will be disabled as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.