@ -11,24 +11,66 @@
// ASSERT that __cplusplus >= 201103L
// ASSERT that __cplusplus >= 201103L
# include <infer_model/common.h>
# include <infer_model/common.h>
# include <infer_model/infer_traits.h>
INFER_NAMESPACE_STD_BEGIN
INFER_NAMESPACE_STD_BEGIN
// use inheritance to avoid compilation errors when using
// use inheritance to avoid compilation errors when using
// methods / non-member functions that are not modeled
// methods / non-member functions that are not modeled
// WARNING: sizeof(shared_ptr) = 24, not 16 - this may
// WARNING: if sizeof(shared_ptr) becomes different than 16, it may
// lead to compilation errors
// lead to compilation errors
template < class T >
template < class T >
class shared_ptr : public std__shared_ptr < T > {
class shared_ptr : public std__shared_ptr < T > {
// translate shared_ptr as type T*
friend class infer_traits : : TranslateAsType < T * > ;
// shared_ptr<T> in infer is translated as T*.
// Some facts:
// 1. shared_ptr<T>* translated as T**
// 2. typeof(this) translated as T**
// 3. typeof(this) in clang's AST is shared_ptr<T>*
// When writing models for shared_ptr, we need to use infer's representation
// In order to achieve that and not break compilation, there is some ugly
// casting going around. We are using void* and void** to make compilation
// happy - infer doesn't care about those types that much since they are
// pointers anyway.
// Example of model_X function declaration:
// static void model_X(infer_shared_ptr_t self, ... params)
// model_X are really C functions, but to simplify linking process, they are
// defined inside shared_ptr class as static methods.
// When using model_X functions, call them like so:
// model_X(__cast_to_infer_ptr(this), args)
/// type of 'this' in shared_ptr<T> as seen by infer
typedef const void * * infer_shared_ptr_t ;
// use it to avoid compilation errors and make infer analyzer happy
# define __cast_to_infer_ptr(self) ((infer_shared_ptr_t)self)
static void model_set ( infer_shared_ptr_t self , const void * value ) {
* self = value ;
}
static void model_copy ( infer_shared_ptr_t self , infer_shared_ptr_t other ) {
/* TODO - increase refcount*/
* self = * other ;
}
static void model_move ( infer_shared_ptr_t self , infer_shared_ptr_t other ) {
model_copy ( self , other ) ;
model_set ( other , nullptr ) ;
}
static T * model_get ( infer_shared_ptr_t self ) { return ( T * ) ( * self ) ; }
static void model_swap ( infer_shared_ptr_t infer_self ,
infer_shared_ptr_t infer_other ) {
const void * t = * infer_self ;
* infer_self = * infer_other ;
* infer_other = t ;
}
public :
public :
# if INFER_USE_LIBCPP
using std__shared_ptr < T > : : __ptr_ ;
# define __data __ptr_
# else
using __shared_ptr < T > : : _M_ptr ;
# define __data _M_ptr
# endif
// Conversion constructors to allow implicit conversions.
// Conversion constructors to allow implicit conversions.
// it's here purely to avoid compilation errors
// it's here purely to avoid compilation errors
template < class Y ,
template < class Y ,
@ -39,7 +81,9 @@ class shared_ptr : public std__shared_ptr<T> {
shared_ptr ( const std__shared_ptr < Y > & r , T * p ) noexcept { }
shared_ptr ( const std__shared_ptr < Y > & r , T * p ) noexcept { }
// constructors:
// constructors:
constexpr shared_ptr ( ) noexcept { __data = nullptr ; }
constexpr shared_ptr ( ) noexcept {
model_set ( __cast_to_infer_ptr ( this ) , nullptr ) ;
}
shared_ptr ( nullptr_t ) : shared_ptr ( ) { }
shared_ptr ( nullptr_t ) : shared_ptr ( ) { }
@ -52,7 +96,7 @@ class shared_ptr : public std__shared_ptr<T> {
template < class Y ,
template < class Y ,
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
explicit shared_ptr ( Y * p ) {
explicit shared_ptr ( Y * p ) {
__data = p ;
model_set ( __cast_to_infer_ptr ( this ) , p ) ;
}
}
template < class Y ,
template < class Y ,
@ -74,27 +118,28 @@ class shared_ptr : public std__shared_ptr<T> {
template < class Y >
template < class Y >
shared_ptr ( const shared_ptr < Y > & r , T * p ) noexcept {
shared_ptr ( const shared_ptr < Y > & r , T * p ) noexcept {
__data = nullptr ; /* TODO */
model_set ( __cast_to_infer_ptr ( this ) , nullptr ) ; /* TODO */
}
}
shared_ptr ( const shared_ptr & r ) noexcept
shared_ptr ( const shared_ptr & r ) noexcept {
: shared_ptr < T > ( r . __data ) { /* TODO - increase refcount*/
model_copy ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
}
}
template < class Y ,
template < class Y ,
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
shared_ptr ( const shared_ptr < Y > & r ) noexcept
shared_ptr ( const shared_ptr < Y > & r ) noexcept {
: shared_ptr < T > ( r . __data ) { /* TODO - increase refcount*/
model_copy ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
}
}
shared_ptr ( shared_ptr & & r ) noexcept : shared_ptr < T > ( r . __data ) {
shared_ptr ( shared_ptr & & r ) noexcept {
r . __data = nullptr ;
model_move ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
}
}
template < class Y ,
template < class Y ,
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
shared_ptr ( shared_ptr < Y > & & r ) noexcept : shared_ptr < T > ( r . __data ) {
shared_ptr ( shared_ptr < Y > & & r ) noexcept {
r . __data = nullptr ;
model_move ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
}
}
template < class Y ,
template < class Y ,
@ -122,7 +167,7 @@ class shared_ptr : public std__shared_ptr<T> {
// assignment:
// assignment:
shared_ptr & operator = ( const shared_ptr & r ) noexcept {
shared_ptr & operator = ( const shared_ptr & r ) noexcept {
// shared_ptr<T>(r).swap(*this);
// shared_ptr<T>(r).swap(*this);
__data = r . __data ;
model_copy ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
return * this ;
return * this ;
}
}
@ -130,13 +175,13 @@ class shared_ptr : public std__shared_ptr<T> {
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
shared_ptr & operator = ( const shared_ptr < Y > & r ) noexcept {
shared_ptr & operator = ( const shared_ptr < Y > & r ) noexcept {
// shared_ptr<T>(r).swap(*this);
// shared_ptr<T>(r).swap(*this);
__data = r . __data ;
model_copy ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
return * this ;
return * this ;
}
}
shared_ptr & operator = ( shared_ptr & & r ) noexcept {
shared_ptr & operator = ( shared_ptr & & r ) noexcept {
// shared_ptr<T>(std::move(r)).swap(*this);
// shared_ptr<T>(std::move(r)).swap(*this);
__data = r . __data ;
model_move ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
return * this ;
return * this ;
}
}
@ -144,7 +189,7 @@ class shared_ptr : public std__shared_ptr<T> {
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
typename = typename enable_if < is_convertible < Y * , T * > : : value > : : type >
shared_ptr & operator = ( shared_ptr < Y > & & r ) {
shared_ptr & operator = ( shared_ptr < Y > & & r ) {
// shared_ptr<T>(std::move(r)).swap(*this);
// shared_ptr<T>(std::move(r)).swap(*this);
__data = r . __data ;
model_move ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
return * this ;
return * this ;
}
}
@ -162,9 +207,7 @@ class shared_ptr : public std__shared_ptr<T> {
// modifiers:
// modifiers:
void swap ( shared_ptr & r ) noexcept {
void swap ( shared_ptr & r ) noexcept {
T * tmp = r . __data ;
model_swap ( __cast_to_infer_ptr ( this ) , __cast_to_infer_ptr ( & r ) ) ;
r . __data = __data ;
__data = tmp ;
}
}
void reset ( ) noexcept { reset ( ( T * ) nullptr ) ; }
void reset ( ) noexcept { reset ( ( T * ) nullptr ) ; }
@ -177,7 +220,7 @@ class shared_ptr : public std__shared_ptr<T> {
delete __data ;
delete __data ;
}
}
*/
*/
__data = p ;
model_set ( __cast_to_infer_ptr ( this ) , p ) ;
// TODO adjust refcounts
// TODO adjust refcounts
}
}
@ -197,14 +240,21 @@ class shared_ptr : public std__shared_ptr<T> {
}
}
// observers:
// observers:
T * get ( ) const noexcept { return __data ; }
T * get ( ) const noexcept { return model_get ( __cast_to_infer_ptr ( this ) ) ; }
typename add_lvalue_reference < T > : : type operator * ( ) const noexcept {
typename add_lvalue_reference < T > : : type operator * ( ) const noexcept {
return * __data ;
return * model_get ( __cast_to_infer_ptr ( this ) ) ;
}
T * operator - > ( ) const noexcept {
return model_get ( __cast_to_infer_ptr ( this ) ) ;
}
}
T * operator - > ( ) const noexcept { return __data ; }
long use_count ( ) const noexcept { return 2 ; /* FIXME */ }
long use_count ( ) const noexcept { return 2 ; /* FIXME */ }
bool unique ( ) const noexcept { return use_count ( ) = = 1 ; /* FIXME */ }
bool unique ( ) const noexcept { return use_count ( ) = = 1 ; /* FIXME */ }
explicit operator bool ( ) const noexcept { return ( bool ) __data ; }
explicit operator bool ( ) const noexcept {
// for some reason analyzer can't cast to bool correctly, trick with two
// negations creates right specs for this function
return ! ! ( bool ) ( model_get ( __cast_to_infer_ptr ( this ) ) ) ;
}
template < class U >
template < class U >
bool owner_before ( shared_ptr < U > const & b ) const {
bool owner_before ( shared_ptr < U > const & b ) const {
return true ; /* FIXME - use non-det*/
return true ; /* FIXME - use non-det*/
@ -334,5 +384,5 @@ shared_ptr<T> make_shared(Args&&... args) {
return shared_ptr < T > ( new T ( std : : forward < Args > ( args ) . . . ) ) ;
return shared_ptr < T > ( new T ( std : : forward < Args > ( args ) . . . ) ) ;
}
}
# undef __ data
# undef __ cast_to_infer_ptr
INFER_NAMESPACE_STD_END
INFER_NAMESPACE_STD_END