Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r75815 - in trunk: boost/icl boost/icl/concept boost/icl/type_traits libs/icl/test libs/icl/test/test_casual_
From: afojgo_at_[hidden]
Date: 2011-12-05 17:59:51


Author: jofaber
Date: 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
New Revision: 75815
URL: http://svn.boost.org/trac/boost/changeset/75815

Log:
Bugfix ticket 6210. In addition: Some changes for introducing move semantics.
Text files modified:
   trunk/boost/icl/concept/interval.hpp | 40 +++++++++++++++++++-------------------
   trunk/boost/icl/impl_config.hpp | 13 ++++-------
   trunk/boost/icl/interval_base_map.hpp | 35 +++++++++++++++++++++++++++++++++
   trunk/boost/icl/interval_base_set.hpp | 1
   trunk/boost/icl/interval_map.hpp | 12 ++++++++++
   trunk/boost/icl/map.hpp | 41 ++++++++++++++++++++++++++++++++++++++-
   trunk/boost/icl/split_interval_map.hpp | 22 +++++++++++++++++++-
   trunk/boost/icl/type_traits/is_numeric.hpp | 1
   trunk/libs/icl/test/fastest_interval_map_cases.hpp | 4 +++
   trunk/libs/icl/test/test_casual_/test_casual.cpp | 20 +++++++++---------
   trunk/libs/icl/test/test_icl_map.hpp | 15 ++++++++++++++
   trunk/libs/icl/test/test_interval_map_shared.hpp | 29 ++++++++++++++++++++++++++++
   12 files changed, 189 insertions(+), 44 deletions(-)

Modified: trunk/boost/icl/concept/interval.hpp
==============================================================================
--- trunk/boost/icl/concept/interval.hpp (original)
+++ trunk/boost/icl/concept/interval.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -609,8 +609,8 @@
     exclusive_less(const Type& left, const Type& right)
     {
         BOOST_ASSERT(!(icl::is_empty(left) || icl::is_empty(right)));
- return domain_less <Type>(left.upper(), right.lower())
- || ( domain_equal<Type>(left.upper(), right.lower())
+ return domain_less <Type>(upper(left), lower(right))
+ || ( domain_equal<Type>(upper(left), lower(right))
                 && inner_bounds(left,right) != interval_bounds::open() );
     }
 
@@ -663,12 +663,12 @@
 {
     return
         (is_left_closed(super.bounds())
- ? domain_less_equal<Type>(super.lower(), element)
- : domain_less<Type>(super.lower(), element))
+ ? domain_less_equal<Type>(lower(super), element)
+ : domain_less<Type>(lower(super), element))
     &&
         (is_right_closed(super.bounds())
- ? domain_less_equal<Type>(element, super.upper())
- : domain_less<Type>(element, super.upper()));
+ ? domain_less_equal<Type>(element, upper(super))
+ : domain_less<Type>(element, upper(super)));
 }
 
 //- within ---------------------------------------------------------------------
@@ -716,8 +716,8 @@
 exclusive_less(const Type& left, const Type& right)
 {
     return icl::is_empty(left) || icl::is_empty(right)
- || domain_less<Type>(left.upper(), right.lower())
- || ( domain_equal<Type>(left.upper(), right.lower())
+ || domain_less<Type>(upper(left), lower(right))
+ || ( domain_equal<Type>(upper(left), lower(right))
             && inner_bounds(left,right) != interval_bounds::open() );
 }
 
@@ -727,7 +727,7 @@
 typename boost::enable_if<has_static_bounds<Type>, bool>::type
 lower_less(const Type& left, const Type& right)
 {
- return domain_less<Type>(left.lower(), right.lower());
+ return domain_less<Type>(lower(left), lower(right));
 }
     
 template<class Type>
@@ -742,9 +742,9 @@
 lower_less(const Type& left, const Type& right)
 {
     if(left_bounds(left,right) == interval_bounds::right_open()) //'[(' == 10
- return domain_less_equal<Type>(left.lower(), right.lower());
+ return domain_less_equal<Type>(lower(left), lower(right));
     else
- return domain_less<Type>(left.lower(), right.lower());
+ return domain_less<Type>(lower(left), lower(right));
 }
     
 
@@ -753,7 +753,7 @@
 typename boost::enable_if<has_static_bounds<Type>, bool>::type
 upper_less(const Type& left, const Type& right)
 {
- return domain_less<Type>(left.upper(), right.upper());
+ return domain_less<Type>(upper(left), upper(right));
 }
 
 template<class Type>
@@ -768,9 +768,9 @@
 upper_less(const Type& left, const Type& right)
 {
     if(right_bounds(left,right) == interval_bounds::left_open())
- return domain_less_equal<Type>(left.upper(), right.upper());
+ return domain_less_equal<Type>(upper(left), upper(right));
     else
- return domain_less<Type>(left.upper(), right.upper());
+ return domain_less<Type>(upper(left), upper(right));
 }
     
 //------------------------------------------------------------------------------
@@ -815,7 +815,7 @@
 typename boost::enable_if<is_asymmetric_interval<Type>, bool>::type
 lower_equal(const Type& left, const Type& right)
 {
- return domain_equal<Type>(left.lower(), right.lower());
+ return domain_equal<Type>(lower(left), lower(right));
 }
 
 template<class Type>
@@ -837,7 +837,7 @@
 lower_equal(const Type& left, const Type& right)
 {
     return (left.bounds().left()==right.bounds().left())
- && domain_equal<Type>(left.lower(), right.lower());
+ && domain_equal<Type>(lower(left), lower(right));
 }
 
 
@@ -846,7 +846,7 @@
 typename boost::enable_if<is_asymmetric_interval<Type>, bool>::type
 upper_equal(const Type& left, const Type& right)
 {
- return domain_equal<Type>(left.upper(), right.upper());
+ return domain_equal<Type>(upper(left), upper(right));
 }
 
 template<class Type>
@@ -868,7 +868,7 @@
 upper_equal(const Type& left, const Type& right)
 {
     return (left.bounds().right()==right.bounds().right())
- && domain_equal<Type>(left.upper(), right.upper());
+ && domain_equal<Type>(upper(left), upper(right));
 }
 
 //------------------------------------------------------------------------------
@@ -951,7 +951,7 @@
 touches(const Type& left, const Type& right)
 {
     return is_complementary(inner_bounds(left,right))
- && domain_equal<Type>(left.upper(), right.lower());
+ && domain_equal<Type>(upper(left), lower(right));
 }
 
 
@@ -1404,7 +1404,7 @@
     if(icl::is_empty(x1) || icl::is_empty(x2))
         return icl::identity_element<DiffT>::value();
     else if(domain_less<Type>(upper(x1), lower(x2)))
- return x2.lower() - x1.upper();
+ return lower(x2) - upper(x1);
     else if(domain_less<Type>(upper(x2), lower(x1)))
         return lower(x1) - upper(x2);
     else

Modified: trunk/boost/icl/impl_config.hpp
==============================================================================
--- trunk/boost/icl/impl_config.hpp (original)
+++ trunk/boost/icl/impl_config.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -25,19 +25,16 @@
 ICL_USE_BOOST_INTERPROCESS_IMPLEMENTATION: Choose set and map implementations
     from boost::interprocess.
 
-ICL_USE_BOOST_MOVE_IMPLEMENTATION: Move aware containers from boost::container
- (NEW) are used. Currently (January 2010) this is only experimental.
- boost::move from the boost::sandbox has to be used. This is depreciated for
- production code, as long as move aware containers are not officially
- accepted into boost.
+ICL_USE_BOOST_MOVE_IMPLEMENTATION: Move aware containers from boost::container.
 +-----------------------------------------------------------------------------*/
 
 #if defined(ICL_USE_BOOST_INTERPROCESS_IMPLEMENTATION)
-#define ICL_IMPL_SPACE boost::interprocess
+# define ICL_IMPL_SPACE boost::interprocess
 #elif defined(ICL_USE_BOOST_MOVE_IMPLEMENTATION)
-#define ICL_IMPL_SPACE boost::container
+# define ICL_IMPL_SPACE boost::container
+# define BOOST_ICL_IS_MOVE_AWARE
 #else
-#define ICL_IMPL_SPACE std
+# define ICL_IMPL_SPACE std
 #endif
 
 #endif // BOOST_ICL_IMPL_CONFIG_HPP_JOFA_091225

Modified: trunk/boost/icl/interval_base_map.hpp
==============================================================================
--- trunk/boost/icl/interval_base_map.hpp (original)
+++ trunk/boost/icl/interval_base_map.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -192,7 +192,12 @@
 
     BOOST_STATIC_CONSTANT(int, fineness = 0);
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ BOOST_COPYABLE_AND_MOVABLE(interval_base_map)
+# endif
+
 public:
+
     //==========================================================================
     //= Construct, copy, destruct
     //==========================================================================
@@ -214,12 +219,40 @@
         BOOST_CONCEPT_ASSERT((EqualComparableConcept<CodomainT>));
     }
 
- /** Assignment operator */
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ /** Move constructor */
+ interval_base_map(BOOST_RV_REF(interval_base_map) src): _map(boost::move(src._map))
+ {
+ std::cout << "."; //CL
+ BOOST_CONCEPT_ASSERT((DefaultConstructibleConcept<DomainT>));
+ BOOST_CONCEPT_ASSERT((LessThanComparableConcept<DomainT>));
+ BOOST_CONCEPT_ASSERT((DefaultConstructibleConcept<CodomainT>));
+ BOOST_CONCEPT_ASSERT((EqualComparableConcept<CodomainT>));
+ }
+
+ /** Copy assignment operator */
+ interval_base_map& operator = (BOOST_COPY_ASSIGN_REF(interval_base_map) src)
+ {
+ this->_map = src._map;
+ return *this;
+ }
+
+ /** Move assignment operator */
+ interval_base_map& operator = (BOOST_RV_REF(interval_base_map) src)
+ {
+ std::cout << ":"; //CL
+ this->_map = boost::move(src._map);
+ return *this;
+ }
+# else //BOOST_ICL_IS_MOVE_AWARE
+
+ /** Copy assignment operator */
     interval_base_map& operator = (const interval_base_map& src)
     {
         this->_map = src._map;
         return *this;
     }
+# endif //BOOST_ICL_IS_MOVE_AWARE
 
     /** swap the content of containers */
     void swap(interval_base_map& object) { _map.swap(object._map); }

Modified: trunk/boost/icl/interval_base_set.hpp
==============================================================================
--- trunk/boost/icl/interval_base_set.hpp (original)
+++ trunk/boost/icl/interval_base_set.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -15,6 +15,7 @@
 #include <boost/interprocess/containers/set.hpp>
 #elif defined(ICL_USE_BOOST_MOVE_IMPLEMENTATION)
 #include <boost/container/set.hpp>
+#include <boost/move/move.hpp> //MOV JODO URG
 #else
 #include <set>
 #endif

Modified: trunk/boost/icl/interval_map.hpp
==============================================================================
--- trunk/boost/icl/interval_map.hpp (original)
+++ trunk/boost/icl/interval_map.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -68,15 +68,26 @@
 
     enum { fineness = 1 };
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ BOOST_COPYABLE_AND_MOVABLE(interval_map)
+# endif
+
 public:
     //==========================================================================
     //= Construct, copy, destruct
     //==========================================================================
+
     /// Default constructor for the empty object
     interval_map(): base_type() {}
+
     /// Copy constructor
     interval_map(const interval_map& src): base_type(src) {}
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ /// Move constructor
+ interval_map(BOOST_RV_REF(interval_map) src)
+ : base_type(boost::move(static_cast<base_type&>(src))){}
+# endif //BOOST_ICL_IS_MOVE_AWARE
 
     /// Copy constructor for base_type
     template<class SubType>
@@ -106,7 +117,6 @@
         typedef interval_base_map<SubType,DomainT,CodomainT,
                                   Traits,Compare,Combine,Section,Interval,Alloc> base_map_type;
         this->clear();
- // Can be implemented via _map.insert: Interval joining not necessary.
         iterator prior_ = this->_map.end();
         ICL_const_FORALL(typename base_map_type, it_, src)
             prior_ = this->add(prior_, *it_);

Modified: trunk/boost/icl/map.hpp
==============================================================================
--- trunk/boost/icl/map.hpp (original)
+++ trunk/boost/icl/map.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -13,11 +13,12 @@
 #if defined(ICL_USE_BOOST_INTERPROCESS_IMPLEMENTATION)
 #include <boost/interprocess/containers/map.hpp>
 #include <boost/interprocess/containers/set.hpp>
-#include <boost/interprocess/containers/flat_set.hpp> //FLAS
+#include <boost/interprocess/containers/flat_set.hpp> //FLAS JODO URG
 #include <boost/interprocess/containers/flat_map.hpp> //FLAS
 #elif defined(ICL_USE_BOOST_MOVE_IMPLEMENTATION)
 #include <boost/container/map.hpp>
 #include <boost/container/set.hpp>
+#include <boost/move/move.hpp> //MOV JODO URG <boost/icl/move.hpp>
 #else
 #include <map>
 #include <set>
@@ -157,6 +158,10 @@
 
     BOOST_STATIC_CONSTANT(int, fineness = 4);
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ BOOST_COPYABLE_AND_MOVABLE(map)
+# endif
+
 public:
     //==========================================================================
     //= Construct, copy, destruct
@@ -189,12 +194,44 @@
         BOOST_CONCEPT_ASSERT((EqualComparableConcept<CodomainT>));
     }
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ map(BOOST_RV_REF(map) src)
+ : base_type(boost::move(static_cast<base_type&>(src)))
+ {
+ std::cout << "m.";//CL
+ BOOST_CONCEPT_ASSERT((DefaultConstructibleConcept<DomainT>));
+ BOOST_CONCEPT_ASSERT((LessThanComparableConcept<DomainT>));
+ BOOST_CONCEPT_ASSERT((DefaultConstructibleConcept<CodomainT>));
+ BOOST_CONCEPT_ASSERT((EqualComparableConcept<CodomainT>));
+ }
+# endif //BOOST_ICL_IS_MOVE_AWARE
+
     explicit map(const element_type& key_value_pair): base_type::map()
     {
         insert(key_value_pair);
     }
 
- map& operator=(const map& src) { base_type::operator=(src); return *this; }
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ map& operator=(BOOST_RV_REF(map) src)
+ {
+ std::cout << "m=";//CL
+ base_type::operator=(static_cast<base_type&>(src));
+ return *this;
+ }
+
+ map& operator=(BOOST_COPY_ASSIGN_REF(map) src)
+ {
+ base_type::operator=(static_cast<const base_type&>(src));
+ return *this;
+ }
+# else
+ map& operator=(const map& src)
+ {
+ base_type::operator=(static_cast<const base_type&>(src));
+ return *this;
+ }
+# endif //BOOST_ICL_IS_MOVE_AWARE
+
     void swap(map& src) { base_type::swap(src); }
 
     //==========================================================================

Modified: trunk/boost/icl/split_interval_map.hpp
==============================================================================
--- trunk/boost/icl/split_interval_map.hpp (original)
+++ trunk/boost/icl/split_interval_map.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -62,35 +62,53 @@
 
     enum { fineness = 3 };
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ BOOST_COPYABLE_AND_MOVABLE(split_interval_map)
+# endif
+
 public:
     //==========================================================================
     //= Construct, copy, destruct
     //==========================================================================
     /// Default constructor for the empty object
     split_interval_map(): base_type() {}
+
     /// Copy constructor
     split_interval_map(const split_interval_map& src): base_type(src) {}
 
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ /// Move constructor
+ split_interval_map(BOOST_RV_REF(split_interval_map) src)
+ : base_type(boost::move(static_cast<base_type&>(src))){}
+# endif
+
     explicit split_interval_map(domain_mapping_type& base_pair): base_type()
     { this->add(base_pair); }
 
     explicit split_interval_map(const value_type& value_pair): base_type()
     { this->add(value_pair); }
 
- /// Assignment operator
+ /// Copy assignment operator
     template<class SubType>
     split_interval_map& operator =
         (const interval_base_map<SubType,DomainT,CodomainT,
                                  Traits,Compare,Combine,Section,Interval,Alloc>& src)
     { this->assign(src); return *this; }
 
+
     /// Assignment from a base interval_map.
     template<class SubType>
     void assign(const interval_base_map<SubType,DomainT,CodomainT,
                                         Traits,Compare,Combine,Section,Interval,Alloc>& src)
     {
         this->clear();
- this->_map.insert(src.begin(), src.end());
+ this->_map.insert(src.begin(), src.end()); //JODO URG new boost.container compiler problem
+ /*hack
+ typedef typename
+ interval_base_map<SubType,DomainT,CodomainT,Traits,Compare,Combine,Section,Interval,Alloc> src_type;
+ ICL_const_FORALL(src_type, it_, src)
+ this->insert(*it_);
+ */
     }
 
 private:

Modified: trunk/boost/icl/type_traits/is_numeric.hpp
==============================================================================
--- trunk/boost/icl/type_traits/is_numeric.hpp (original)
+++ trunk/boost/icl/type_traits/is_numeric.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -10,6 +10,7 @@
 
 #include <limits>
 #include <complex>
+#include <functional>
 #include <boost/type_traits/is_floating_point.hpp>
 #include <boost/type_traits/ice.hpp>
 #include <boost/type_traits/is_integral.hpp>

Modified: trunk/libs/icl/test/fastest_interval_map_cases.hpp
==============================================================================
--- trunk/libs/icl/test/fastest_interval_map_cases.hpp (original)
+++ trunk/libs/icl/test/fastest_interval_map_cases.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -92,6 +92,10 @@
 (fastest_icl_interval_map_intersects_4_bicremental_types)
 { interval_map_intersects_4_bicremental_types<INTERVAL_MAP, bicremental_type_3, int>();}
 
+BOOST_AUTO_TEST_CASE
+(fastest_icl_interval_map_move_4_bicremental_types)
+{ interval_map_move_4_bicremental_types<INTERVAL_MAP, bicremental_type_1, double>();}
+
 
 #endif // BOOST_ICL_FASTEST_INTERVAL_MAP_CASES_HPP_JOFA_090702
 

Modified: trunk/libs/icl/test/test_casual_/test_casual.cpp
==============================================================================
--- trunk/libs/icl/test/test_casual_/test_casual.cpp (original)
+++ trunk/libs/icl/test/test_casual_/test_casual.cpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -41,14 +41,14 @@
 
 void pass_it(shared_ptr<int> pi)
 {
- *pi = 41;
- cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
+ *pi = 41;
+ cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
 }
 
 void pass_it_ref(shared_ptr<int>& pi)
 {
- *pi = 43;
- cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
+ *pi = 43;
+ cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
 }
 
 BOOST_AUTO_TEST_CASE(casual)
@@ -59,10 +59,10 @@
     typedef interval_set<T> IntervalSetT;
     typedef IntervalMapT::interval_type IntervalT;
 
- shared_ptr<int> pi(new int(42));
- cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
- pass_it(pi);
- pass_it_ref(pi);
+ shared_ptr<int> pi(new int(42));
+ cout << "uses: " << pi.use_count() << " cont: " << *pi << endl;
+ pass_it(pi);
+ pass_it_ref(pi);
 
     BOOST_CHECK_EQUAL(true, true);
 }
@@ -76,9 +76,9 @@
 
     Value const max(Limits::max());
 
- Interval::interval_type piff = Interval::open(max, max);
+ Interval::interval_type piff = Interval::open(max, max);
 
- BOOST_CHECK(!icl::is_empty(Interval::open(max - 2, max)));
+ BOOST_CHECK(!icl::is_empty(Interval::open(max - 2, max)));
     BOOST_CHECK( icl::is_empty(Interval::open(max - 1, max)));
     BOOST_CHECK( icl::is_empty(Interval::open(max, max)));
 }

Modified: trunk/libs/icl/test/test_icl_map.hpp
==============================================================================
--- trunk/libs/icl/test/test_icl_map.hpp (original)
+++ trunk/libs/icl/test/test_icl_map.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -43,6 +43,21 @@
 
     //BOOST_CHECK_EQUAL( found == map_a.end(), true );
     //BOOST_CHECK_EQUAL( map_a(MK_v(5)), MK_u(0) );
+
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+
+ cout << ">"; //JODO
+ MapT map_b(boost::move(MapT().add(key_value_pair)));
+ cout << "<\n";
+ cout << map_b << endl;
+
+ cout << ">";
+ MapT map_c;
+ map_c = boost::move(MapT().add(key_value_pair));
+ cout << "<\n";
+ cout << map_c << endl;
+
+# endif //BOOST_ICL_IS_MOVE_AWARE
 }
 
 

Modified: trunk/libs/icl/test/test_interval_map_shared.hpp
==============================================================================
--- trunk/libs/icl/test/test_interval_map_shared.hpp (original)
+++ trunk/libs/icl/test/test_interval_map_shared.hpp 2011-12-05 17:59:49 EST (Mon, 05 Dec 2011)
@@ -1516,5 +1516,34 @@
 }
 
 
+template
+<
+#if (defined(__GNUC__) && (__GNUC__ < 4)) //MEMO Can be simplified, if gcc-3.4 is obsolete
+ ICL_IntervalMap_TEMPLATE(T,U,Traits,partial_absorber) IntervalMap,
+#else
+ ICL_IntervalMap_TEMPLATE(_T,_U,Traits,partial_absorber) IntervalMap,
+#endif
+ class T, class U
+>
+void interval_map_move_4_bicremental_types()
+{
+ typedef IntervalMap<T,U> IntervalMapT;
+ typedef typename IntervalMapT::interval_type IntervalT;
+
+# ifdef BOOST_ICL_IS_MOVE_AWARE
+ IntervalMapT map_A(boost::move(static_cast<IntervalMapT&>(IntervalMapT(IDv(0,4,2)))));
+ IntervalMapT map_B(boost::move(static_cast<IntervalMapT&>(IntervalMapT(IDv(0,2,1)).add(IDv(2,4,1)).add(IDv(0,4,1)))));
+
+ BOOST_CHECK_EQUAL( map_A, map_B );
+
+ map_A = boost::move(static_cast<IntervalMapT&>(IntervalMapT(IIv(1,4,2)))); //JODO not yet moving
+ map_B = boost::move(static_cast<IntervalMapT&>(IntervalMapT(CIv(0,2,1)).insert(IDv(3,5,1)).add(CDv(0,5,1))));
+
+ BOOST_CHECK_EQUAL( map_A, map_B );
+# endif //BOOST_ICL_IS_MOVE_AWARE
+}
+
+
+
 #endif // LIBS_ICL_TEST_TEST_INTERVAL_MAP_SHARED_HPP_JOFA_081005
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk