| 1 | /* Boost.Flyweight basic test template. |
| 2 | * |
| 3 | * Copyright 2006-2023 Joaquin M Lopez Munoz. |
| 4 | * Distributed under the Boost Software License, Version 1.0. |
| 5 | * (See accompanying file LICENSE_1_0.txt or copy at |
| 6 | * http://www.boost.org/LICENSE_1_0.txt) |
| 7 | * |
| 8 | * See http://www.boost.org/libs/flyweight for library home page. |
| 9 | */ |
| 10 | |
| 11 | #ifndef BOOST_FLYWEIGHT_TEST_BASIC_TEMPLATE_HPP |
| 12 | #define BOOST_FLYWEIGHT_TEST_BASIC_TEMPLATE_HPP |
| 13 | |
| 14 | #if defined(_MSC_VER) |
| 15 | #pragma once |
| 16 | #endif |
| 17 | |
| 18 | #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */ |
| 19 | #include <boost/detail/lightweight_test.hpp> |
| 20 | #include <boost/flyweight/key_value.hpp> |
| 21 | #include <boost/mpl/apply.hpp> |
| 22 | #include <boost/utility/value_init.hpp> |
| 23 | #include <string> |
| 24 | #include <sstream> |
| 25 | #include "heavy_objects.hpp" |
| 26 | |
| 27 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 28 | #include <utility> |
| 29 | #endif |
| 30 | |
| 31 | #if !defined(BOOST_FLYWEIGHT_DISABLE_HASH_SUPPORT) |
| 32 | #include <boost/functional/hash.hpp> |
| 33 | |
| 34 | #if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) |
| 35 | #include <functional> |
| 36 | #endif |
| 37 | #endif |
| 38 | |
| 39 | #define LENGTHOF(array) (sizeof(array)/sizeof((array)[0])) |
| 40 | |
| 41 | template<typename Flyweight,typename ForwardIterator> |
| 42 | void test_basic_template( |
| 43 | ForwardIterator first,ForwardIterator last |
| 44 | BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight)) |
| 45 | { |
| 46 | typedef typename Flyweight::value_type value_type; |
| 47 | |
| 48 | ForwardIterator it; |
| 49 | |
| 50 | for(it=first;it!=last;++it){ |
| 51 | /* construct/copy/destroy */ |
| 52 | |
| 53 | Flyweight f1(*it); |
| 54 | Flyweight f2; |
| 55 | Flyweight c1(f1); |
| 56 | const Flyweight c2(static_cast<const Flyweight&>(f2)); |
| 57 | value_type v1(*it); |
| 58 | boost::value_initialized<value_type> v2; |
| 59 | BOOST_TEST(f1.get_key()==*it); |
| 60 | BOOST_TEST((f1==f2)==(f1.get()==v2.data())); |
| 61 | BOOST_TEST(f1==c1); |
| 62 | BOOST_TEST(f2==c2); |
| 63 | |
| 64 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 65 | Flyweight cr1(std::move(c1)); |
| 66 | Flyweight cr2(std::move(c2)); |
| 67 | BOOST_TEST(f1==cr1); |
| 68 | BOOST_TEST(f2==cr2); |
| 69 | #endif |
| 70 | |
| 71 | #if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) |
| 72 | /* testcase for https://svn.boost.org/trac/boost/ticket/10439 */ |
| 73 | |
| 74 | Flyweight f3={}; |
| 75 | BOOST_TEST(f3==f2); |
| 76 | #endif |
| 77 | |
| 78 | f1=((void)0,f1); /* self assignment warning */ |
| 79 | BOOST_TEST(f1==f1); |
| 80 | |
| 81 | c1=f2; |
| 82 | BOOST_TEST(c1==f2); |
| 83 | |
| 84 | c1=f1; |
| 85 | BOOST_TEST(c1==f1); |
| 86 | |
| 87 | /* convertibility to underlying type */ |
| 88 | |
| 89 | BOOST_TEST(f1.get()==v1); |
| 90 | BOOST_TEST(*f1==v1); |
| 91 | |
| 92 | /* identity of reference */ |
| 93 | |
| 94 | BOOST_TEST(&f1.get()==&c1.get()); |
| 95 | BOOST_TEST(&(*f1)==&c1.get()); |
| 96 | BOOST_TEST(f1.operator->()==&c1.get()); |
| 97 | |
| 98 | /* modifiers */ |
| 99 | |
| 100 | f1.swap(f1); |
| 101 | BOOST_TEST(f1==c1); |
| 102 | |
| 103 | f1.swap(f2); |
| 104 | BOOST_TEST(f1==c2); |
| 105 | BOOST_TEST(f2==c1); |
| 106 | |
| 107 | boost::flyweights::swap(f1,f2); |
| 108 | BOOST_TEST(f1==c1); |
| 109 | BOOST_TEST(f2==c2); |
| 110 | |
| 111 | /* specialized algorithms */ |
| 112 | |
| 113 | std::ostringstream oss1; |
| 114 | oss1<<f1; |
| 115 | std::ostringstream oss2; |
| 116 | oss2<<f1.get(); |
| 117 | BOOST_TEST(oss1.str()==oss2.str()); |
| 118 | |
| 119 | #if !defined(BOOST_FLYWEIGHT_DISABLE_HASH_SUPPORT) |
| 120 | |
| 121 | /* hash support */ |
| 122 | |
| 123 | BOOST_TEST(boost::hash<Flyweight>()(f1)==boost::hash<Flyweight>()(c1)); |
| 124 | BOOST_TEST(boost::hash<Flyweight>()(f1)== |
| 125 | boost::hash<const value_type*>()(&f1.get())); |
| 126 | |
| 127 | #if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) |
| 128 | BOOST_TEST(std::hash<Flyweight>()(f1)==std::hash<Flyweight>()(c1)); |
| 129 | BOOST_TEST(std::hash<Flyweight>()(f1)== |
| 130 | std::hash<const value_type*>()(&f1.get())); |
| 131 | #endif |
| 132 | #endif |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | template<typename Flyweight,typename ForwardIterator> |
| 137 | void test_basic_with_assign_template( |
| 138 | ForwardIterator first,ForwardIterator last |
| 139 | BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight)) |
| 140 | { |
| 141 | typedef typename Flyweight::value_type value_type; |
| 142 | |
| 143 | ForwardIterator it; |
| 144 | |
| 145 | test_basic_template<Flyweight>(first,last); |
| 146 | |
| 147 | for(it=first;it!=last;++it){ |
| 148 | /* value construction */ |
| 149 | |
| 150 | value_type v(*it); |
| 151 | Flyweight f1(v); |
| 152 | Flyweight f2(f1.get()); |
| 153 | BOOST_TEST(f1.get()==v); |
| 154 | BOOST_TEST(f2.get()==v); |
| 155 | BOOST_TEST(f1==f2); |
| 156 | |
| 157 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 158 | value_type v1(v); |
| 159 | const value_type v2(v); |
| 160 | Flyweight fr1(std::move(v1)); |
| 161 | Flyweight fr2(std::move(v2)); |
| 162 | BOOST_TEST(fr1==v); |
| 163 | BOOST_TEST(fr2==v); |
| 164 | #endif |
| 165 | |
| 166 | /* value assignment */ |
| 167 | |
| 168 | Flyweight f3,f4; |
| 169 | f3=v; |
| 170 | f4=f1.get(); |
| 171 | BOOST_TEST(f2.get()==v); |
| 172 | BOOST_TEST(f3.get()==v); |
| 173 | BOOST_TEST(f2==f3); |
| 174 | |
| 175 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 176 | Flyweight fr3; |
| 177 | fr3=value_type(*it); |
| 178 | BOOST_TEST(fr3.get()==value_type(*it)); |
| 179 | #endif |
| 180 | |
| 181 | /* specialized algorithms */ |
| 182 | |
| 183 | std::ostringstream oss1; |
| 184 | oss1<<f1; |
| 185 | std::istringstream iss1(oss1.str()); |
| 186 | Flyweight f5; |
| 187 | iss1>>f5; |
| 188 | BOOST_TEST(f5==f1); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | template< |
| 193 | typename Flyweight1,typename Flyweight2, |
| 194 | typename ForwardIterator1,typename ForwardIterator2 |
| 195 | > |
| 196 | void test_basic_comparison_template( |
| 197 | ForwardIterator1 first1,ForwardIterator1 last1, |
| 198 | ForwardIterator2 first2 |
| 199 | BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight1) |
| 200 | BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Flyweight2)) |
| 201 | { |
| 202 | typedef typename Flyweight1::value_type value_type1; |
| 203 | typedef typename Flyweight2::value_type value_type2; |
| 204 | |
| 205 | for(;first1!=last1;++first1,++first2){ |
| 206 | value_type1 v1=value_type1(*first1); |
| 207 | value_type2 v2=value_type2(*first2); |
| 208 | Flyweight1 f1(v1); |
| 209 | Flyweight2 f2(v2); |
| 210 | |
| 211 | BOOST_TEST((f1==f2)==(f1.get()==v2)); |
| 212 | BOOST_TEST((f1< f2)==(f1.get()< v2)); |
| 213 | BOOST_TEST((f1!=f2)==(f1.get()!=v2)); |
| 214 | BOOST_TEST((f1> f2)==(f1.get()> v2)); |
| 215 | BOOST_TEST((f1>=f2)==(f1.get()>=v2)); |
| 216 | BOOST_TEST((f1<=f2)==(f1.get()<=v2)); |
| 217 | |
| 218 | #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) |
| 219 | BOOST_TEST((f1==v2)==(f1.get()==v2)); |
| 220 | BOOST_TEST((f1< v2)==(f1.get()< v2)); |
| 221 | BOOST_TEST((f1!=v2)==(f1.get()!=v2)); |
| 222 | BOOST_TEST((f1> v2)==(f1.get()> v2)); |
| 223 | BOOST_TEST((f1>=v2)==(f1.get()>=v2)); |
| 224 | BOOST_TEST((f1<=v2)==(f1.get()<=v2)); |
| 225 | |
| 226 | BOOST_TEST((v1==f2)==(f1.get()==v2)); |
| 227 | BOOST_TEST((v1< f2)==(f1.get()< v2)); |
| 228 | BOOST_TEST((v1!=f2)==(f1.get()!=v2)); |
| 229 | BOOST_TEST((v1> f2)==(f1.get()> v2)); |
| 230 | BOOST_TEST((v1>=f2)==(f1.get()>=v2)); |
| 231 | BOOST_TEST((v1<=f2)==(f1.get()<=v2)); |
| 232 | #endif |
| 233 | |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | template<typename FlyweightSpecifier> |
| 238 | void test_basic_template(BOOST_EXPLICIT_TEMPLATE_TYPE(FlyweightSpecifier)) |
| 239 | { |
| 240 | typedef typename boost::mpl::apply1< |
| 241 | FlyweightSpecifier,int |
| 242 | >::type int_flyweight; |
| 243 | |
| 244 | typedef typename boost::mpl::apply1< |
| 245 | FlyweightSpecifier,std::string |
| 246 | >::type string_flyweight; |
| 247 | |
| 248 | typedef typename boost::mpl::apply1< |
| 249 | FlyweightSpecifier,char |
| 250 | >::type char_flyweight; |
| 251 | |
| 252 | typedef typename boost::mpl::apply1< |
| 253 | FlyweightSpecifier, |
| 254 | boost::flyweights::key_value<std::string,texture,from_texture_to_string> |
| 255 | >::type texture_flyweight; |
| 256 | |
| 257 | typedef typename boost::mpl::apply1< |
| 258 | FlyweightSpecifier, |
| 259 | boost::flyweights::key_value<int,factorization> |
| 260 | >::type factorization_flyweight; |
| 261 | |
| 262 | int ints[]={0,1,1,0,1,2,3,4,3,4,0,0}; |
| 263 | test_basic_with_assign_template<int_flyweight>( |
| 264 | &ints[0],&ints[0]+LENGTHOF(ints)); |
| 265 | |
| 266 | const char* words[]={"hello" ,"boost" ,"flyweight" ,"boost" ,"bye" ,"c++" ,"c++" }; |
| 267 | test_basic_with_assign_template<string_flyweight>( |
| 268 | &words[0],&words[0]+LENGTHOF(words)); |
| 269 | |
| 270 | const char* textures[]={"wood" ,"grass" ,"sand" ,"granite" ,"terracotta" }; |
| 271 | test_basic_with_assign_template<texture_flyweight>( |
| 272 | &textures[0],&textures[0]+LENGTHOF(textures)); |
| 273 | |
| 274 | int factorizations[]={1098,102387,90846,2223978}; |
| 275 | test_basic_template<factorization_flyweight>( |
| 276 | &factorizations[0],&factorizations[0]+LENGTHOF(factorizations)); |
| 277 | |
| 278 | char chars[]={0,2,4,5,1,1,1,3,4,1,1,0}; |
| 279 | test_basic_comparison_template<int_flyweight,char_flyweight>( |
| 280 | &ints[0],&ints[0]+LENGTHOF(ints),&chars[0]); |
| 281 | |
| 282 | test_basic_comparison_template<string_flyweight,string_flyweight>( |
| 283 | &words[0],&words[0]+LENGTHOF(words)-1,&words[1]); |
| 284 | |
| 285 | test_basic_comparison_template<texture_flyweight,texture_flyweight>( |
| 286 | &textures[0],&textures[0]+LENGTHOF(textures)-1,&textures[1]); |
| 287 | |
| 288 | #if !defined(BOOST_NO_EXCEPTIONS) |
| 289 | typedef typename boost::mpl::apply1< |
| 290 | FlyweightSpecifier, |
| 291 | boost::flyweights::key_value<int,throwing_value,from_throwing_value_to_int> |
| 292 | >::type throwing_flyweight; |
| 293 | |
| 294 | try{ |
| 295 | throwing_flyweight fw(0); |
| 296 | }catch(const throwing_value_exception&){} |
| 297 | try{ |
| 298 | throwing_flyweight fw=throwing_flyweight(throwing_value()); |
| 299 | (void)fw; |
| 300 | }catch(const throwing_value_exception&){} |
| 301 | #endif |
| 302 | |
| 303 | } |
| 304 | |
| 305 | #undef LENGTHOF |
| 306 | |
| 307 | #endif |
| 308 | |