forked from Alepha/Alepha
216 lines
6.4 KiB
C++
216 lines
6.4 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
/*!
|
|
* @file
|
|
* @brief The `Attestation` framework permits code which can provide limited compiletime guarantees of conditions.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
|
|
#include <utility>
|
|
#include <type_traits>
|
|
|
|
|
|
namespace Alepha::Proof
|
|
{
|
|
template< typename Attestation >
|
|
Attestation
|
|
impute()
|
|
{
|
|
return Attestation{};
|
|
}
|
|
|
|
template< typename Permission >
|
|
auto
|
|
attest( Permission )
|
|
{
|
|
return impute< typename Permission::attestation_type >();
|
|
}
|
|
|
|
#if 0
|
|
namespace attestation_detail
|
|
{
|
|
template< typename ... Args > struct typelist {};
|
|
|
|
template< typename T > struct make_typelist;
|
|
|
|
template< typename ... Args >
|
|
struct make_typelist< std::tuple< Args... > >
|
|
{
|
|
using type= typelist< Args... >;
|
|
};
|
|
|
|
template< typename Policy, typename = void >
|
|
struct conjugates
|
|
{
|
|
using type= typelist< Policy >;
|
|
};
|
|
|
|
template< typename Policy >
|
|
struct conjugates< Policy, std::void_t< decltype( typename Policy::conjunction_type{} ) > >
|
|
{
|
|
using type= typename make_typelist< typename Policy::conjunction_type >::type;
|
|
};
|
|
|
|
|
|
template< typename value, typename Conjugates >
|
|
struct in_set : std::false_type {};
|
|
|
|
template< typename value >
|
|
struct in_set< value, typelist< value > > : std::true_type {};
|
|
|
|
template< typename value, typename ... Conjugates >
|
|
struct in_set< value, typelist< value, Conjugates... > > : std::true_type {};
|
|
|
|
template< typename value, typename X, typename ... Conjugates >
|
|
struct in_set< value, typelist< X, Conjugates... > > : in_set< value, Conjugates... > {};
|
|
|
|
template< typename value, typename X >
|
|
struct in_set< value, typelist< X > > : std::false_type {};
|
|
|
|
template< typename A, typename B >
|
|
struct is_subset_of : std::false_type {};
|
|
|
|
template< typename T, typename ... Left, typename ... Right >
|
|
struct is_subset_of< typelist< T, Left... >, typelist< Right... > >
|
|
: std::integral_constant< bool, in_set< T, Right... >::value
|
|
&& is_subset_of< Left..., Right... > > {};
|
|
|
|
template< typename ... Right >
|
|
struct is_subset_of< typelist<>, typelist< Right... > >
|
|
: std::true_type {};
|
|
|
|
template< typename ... Left >
|
|
struct is_subset_of< typelist< Left... >, typelist<> >
|
|
: std::false_type {};
|
|
|
|
template<>
|
|
struct is_subset_of< typelist<>, typelist<> > : std::true_type {};
|
|
|
|
template< typename ... lists >
|
|
struct set_union;
|
|
|
|
template< typename ... elements >
|
|
struct set_union< typelist< elements... > > : typelist< elements... > {};
|
|
|
|
template< typename ... elements >
|
|
struct set_union< typelist< elements... > > : typelist< elements... > {};
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
* @brief An Attestation is a representation of some particular fact about runtime code known at compiletime.
|
|
*
|
|
* An Attestation is a copyable, zero-storage type which represents at compiletime a fact about runtime code.
|
|
* Attestations can be used as compiletime predicates for a function by making that function take an attestation
|
|
* as an argument. Every attestation is created only by the limited set of classes as indicated by the `averant`
|
|
* member of the `Policy` for an Attestation. These policies are also tag types which distinguish the kind of
|
|
* Attestation.
|
|
*
|
|
* Attestations can be copied freely, as any fact once true is considered to continue being true. Attestations
|
|
* should not be held over the long term -- they are best used as temporaries, such as ephemeral arguments to
|
|
* a function requiring that fact to be true.
|
|
*/
|
|
template< typename Policy >
|
|
class Attestation
|
|
{
|
|
private:
|
|
struct permission_t { using attestation_type= Attestation; };
|
|
static inline permission_t permission;
|
|
|
|
Attestation()= default;
|
|
|
|
template< typename A > friend A impute();
|
|
|
|
//template< typename A, typename P > friend A attest( P );
|
|
|
|
friend typename Policy::averant;
|
|
|
|
//using conjugates= typename attestation_detail::conjugates< Policy >::type;
|
|
|
|
template< typename > friend class Attestation;
|
|
|
|
public:
|
|
template< typename > class Witness;
|
|
|
|
#if 0
|
|
template< typename ... Policies >
|
|
Attestation( Attestation< Policies >... )
|
|
{
|
|
static_assert( attestation_detail::is_subset_of< conjugates,
|
|
typename attestation_detail::set_union< Policies >::type >::value,
|
|
"Cannot make an attestation without sufficient proof of existance for "
|
|
"required facts." );
|
|
}
|
|
|
|
template< typename ForeignPolicy >
|
|
Attestation( Attestation< ForeignPolicy > )
|
|
//: Attestation( attestation_detail::expand< ForeignPolicy >::
|
|
{
|
|
static_assert( attestation_detail::is_subset_of< conjugates,
|
|
typelist< Attestations... > >::value, "Cannot make an attestation without "
|
|
"sufficient proof of existance for required facts." );
|
|
}
|
|
#endif
|
|
|
|
template< typename T >
|
|
auto
|
|
aver( const T &r )
|
|
{
|
|
return Witness< const T & >( r );
|
|
}
|
|
|
|
template< typename T >
|
|
auto
|
|
averCopy( T r )
|
|
{
|
|
return Witness< T >( std::move( r ) );
|
|
}
|
|
};
|
|
|
|
/*!
|
|
* @brief A witness knows a fact (Attestation) to be true about some particular value.
|
|
*
|
|
* In the Attestation framework, a Witness is an attestation type which binds a particular fact (a regular Attestation) to the
|
|
* value for which that fact is true. For example, one can create a `Witness` to the fact that a particular `std::vector` is
|
|
* sorted. This is extremely useful as it cuts down on the need to create specialized "constrained" types for specific use cases.
|
|
*
|
|
* Witnesses are not actually a proxy for the value for which the fact is true. A witness must `testify` as to which value the
|
|
* fact is actually true for. The `testify` function returns the actual value for which the `Attestation` is known to hold.
|
|
*/
|
|
template< typename Policy >
|
|
template< typename T >
|
|
class Attestation< Policy >::Witness
|
|
{
|
|
private:
|
|
T value;
|
|
|
|
friend Attestation< Policy >;
|
|
|
|
explicit Witness( T i_v ) : value( std::move( i_v ) ) {}
|
|
|
|
public:
|
|
inline friend T &testify( Witness &w ) noexcept { return w.value; }
|
|
inline friend T const &testify( const Witness &w ) noexcept { return w.value; }
|
|
inline friend Attestation< Policy > fact( Witness w ) noexcept
|
|
{ return Attestation< Policy >{}; }
|
|
};
|
|
|
|
template< typename Policy >
|
|
template< typename T >
|
|
class Attestation< Policy >::Witness< T & >
|
|
{
|
|
private:
|
|
T *p;
|
|
|
|
friend Attestation< Policy >;
|
|
|
|
explicit Witness( T &r ) : p( &r ) {}
|
|
|
|
public:
|
|
friend T &testify( Witness w ) noexcept { return *w.p; }
|
|
friend Attestation< Policy > fact( Witness w ) noexcept { return Attestation< Policy >{}; }
|
|
};
|
|
}
|