From 38be0d13830efd2d98281c645c3a60afe05ffece Mon Sep 17 00:00:00 2001 From: Qt by Nokia Date: Wed, 27 Apr 2011 12:05:43 +0200 Subject: Initial import from the monolithic Qt. This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12 --- src/corelib/QtCore.dynlist | 10 + src/corelib/animation/animation.pri | 25 + src/corelib/animation/qabstractanimation.cpp | 1055 +++ src/corelib/animation/qabstractanimation.h | 172 + src/corelib/animation/qabstractanimation_p.h | 233 + src/corelib/animation/qanimationgroup.cpp | 302 + src/corelib/animation/qanimationgroup.h | 88 + src/corelib/animation/qanimationgroup_p.h | 96 + src/corelib/animation/qparallelanimationgroup.cpp | 347 + src/corelib/animation/qparallelanimationgroup.h | 86 + src/corelib/animation/qparallelanimationgroup_p.h | 93 + src/corelib/animation/qpauseanimation.cpp | 155 + src/corelib/animation/qpauseanimation.h | 84 + src/corelib/animation/qpropertyanimation.cpp | 317 + src/corelib/animation/qpropertyanimation.h | 89 + src/corelib/animation/qpropertyanimation_p.h | 90 + .../animation/qsequentialanimationgroup.cpp | 588 ++ src/corelib/animation/qsequentialanimationgroup.h | 96 + .../animation/qsequentialanimationgroup_p.h | 114 + src/corelib/animation/qvariantanimation.cpp | 701 ++ src/corelib/animation/qvariantanimation.h | 130 + src/corelib/animation/qvariantanimation_p.h | 124 + src/corelib/arch/alpha/arch.pri | 4 + src/corelib/arch/alpha/qatomic_alpha.s | 239 + src/corelib/arch/arch.pri | 38 + src/corelib/arch/arm/arch.pri | 4 + src/corelib/arch/arm/qatomic_arm.cpp | 72 + src/corelib/arch/avr32/arch.pri | 3 + src/corelib/arch/bfin/arch.pri | 3 + src/corelib/arch/generic/arch.pri | 6 + src/corelib/arch/generic/qatomic_generic_unix.cpp | 123 + .../arch/generic/qatomic_generic_windows.cpp | 131 + src/corelib/arch/i386/arch.pri | 4 + src/corelib/arch/i386/qatomic_i386.s | 103 + src/corelib/arch/ia64/arch.pri | 4 + src/corelib/arch/ia64/qatomic_ia64.s | 74 + src/corelib/arch/integrity/arch.pri | 3 + src/corelib/arch/macosx/arch.pri | 6 + src/corelib/arch/macosx/qatomic32_ppc.s | 169 + src/corelib/arch/mips/arch.pri | 8 + src/corelib/arch/mips/qatomic_mips32.s | 150 + src/corelib/arch/mips/qatomic_mips64.s | 138 + src/corelib/arch/parisc/arch.pri | 5 + src/corelib/arch/parisc/q_ldcw.s | 62 + src/corelib/arch/parisc/qatomic_parisc.cpp | 88 + src/corelib/arch/powerpc/arch.pri | 10 + src/corelib/arch/powerpc/qatomic32.s | 525 ++ src/corelib/arch/powerpc/qatomic64.s | 533 ++ src/corelib/arch/qatomic_alpha.h | 642 ++ src/corelib/arch/qatomic_arch.h | 101 + src/corelib/arch/qatomic_arm.h | 76 + src/corelib/arch/qatomic_armv5.h | 431 + src/corelib/arch/qatomic_armv6.h | 559 ++ src/corelib/arch/qatomic_armv7.h | 61 + src/corelib/arch/qatomic_avr32.h | 252 + src/corelib/arch/qatomic_bfin.h | 343 + src/corelib/arch/qatomic_bootstrap.h | 99 + src/corelib/arch/qatomic_generic.h | 282 + src/corelib/arch/qatomic_i386.h | 361 + src/corelib/arch/qatomic_ia64.h | 813 ++ src/corelib/arch/qatomic_integrity.h | 289 + src/corelib/arch/qatomic_macosx.h | 57 + src/corelib/arch/qatomic_mips.h | 892 ++ src/corelib/arch/qatomic_parisc.h | 305 + src/corelib/arch/qatomic_powerpc.h | 648 ++ src/corelib/arch/qatomic_s390.h | 426 + src/corelib/arch/qatomic_sh.h | 330 + src/corelib/arch/qatomic_sh4a.h | 537 ++ src/corelib/arch/qatomic_sparc.h | 525 ++ src/corelib/arch/qatomic_symbian.h | 313 + src/corelib/arch/qatomic_vxworks.h | 318 + src/corelib/arch/qatomic_windows.h | 496 + src/corelib/arch/qatomic_windowsce.h | 56 + src/corelib/arch/qatomic_x86_64.h | 363 + src/corelib/arch/s390/arch.pri | 3 + src/corelib/arch/sh/arch.pri | 4 + src/corelib/arch/sh/qatomic_sh.cpp | 72 + src/corelib/arch/sh4a/arch.pri | 3 + src/corelib/arch/sparc/arch.pri | 10 + src/corelib/arch/sparc/qatomic32.s | 103 + src/corelib/arch/sparc/qatomic64.s | 327 + src/corelib/arch/sparc/qatomic_sparc.cpp | 92 + src/corelib/arch/symbian/arch.pri | 18 + src/corelib/arch/symbian/common_p.h | 106 + src/corelib/arch/symbian/debugfunction.cpp | 1143 +++ src/corelib/arch/symbian/dla_p.h | 969 ++ src/corelib/arch/symbian/heap_hybrid.cpp | 3346 +++++++ src/corelib/arch/symbian/heap_hybrid_p.h | 406 + src/corelib/arch/symbian/page_alloc_p.h | 68 + src/corelib/arch/symbian/qatomic_generic_armv6.cpp | 472 + src/corelib/arch/symbian/qatomic_symbian.cpp | 527 ++ src/corelib/arch/symbian/qt_heapsetup_symbian.cpp | 105 + src/corelib/arch/symbian/qt_hybridheap_symbian_p.h | 178 + src/corelib/arch/symbian/slab_p.h | 125 + src/corelib/arch/vxworks/arch.pri | 6 + src/corelib/arch/vxworks/qatomic_ppc.s | 415 + src/corelib/arch/windows/arch.pri | 3 + src/corelib/arch/x86_64/arch.pri | 4 + src/corelib/arch/x86_64/qatomic_sun.s | 91 + src/corelib/codecs/codecs.pri | 59 + src/corelib/codecs/codecs.qdoc | 532 ++ src/corelib/codecs/qfontlaocodec.cpp | 123 + src/corelib/codecs/qfontlaocodec_p.h | 78 + src/corelib/codecs/qiconvcodec.cpp | 548 ++ src/corelib/codecs/qiconvcodec_p.h | 104 + src/corelib/codecs/qisciicodec.cpp | 285 + src/corelib/codecs/qisciicodec_p.h | 81 + src/corelib/codecs/qlatincodec.cpp | 244 + src/corelib/codecs/qlatincodec_p.h | 94 + src/corelib/codecs/qsimplecodec.cpp | 735 ++ src/corelib/codecs/qsimplecodec_p.h | 91 + src/corelib/codecs/qtextcodec.cpp | 1878 ++++ src/corelib/codecs/qtextcodec.h | 198 + src/corelib/codecs/qtextcodec_p.h | 111 + src/corelib/codecs/qtextcodec_symbian.cpp | 689 ++ src/corelib/codecs/qtextcodecplugin.cpp | 161 + src/corelib/codecs/qtextcodecplugin.h | 96 + src/corelib/codecs/qtsciicodec.cpp | 498 + src/corelib/codecs/qtsciicodec_p.h | 106 + src/corelib/codecs/qutfcodec.cpp | 670 ++ src/corelib/codecs/qutfcodec_p.h | 170 + src/corelib/concurrent/concurrent.pri | 42 + src/corelib/concurrent/qfuture.cpp | 697 ++ src/corelib/concurrent/qfuture.h | 278 + src/corelib/concurrent/qfutureinterface.cpp | 565 ++ src/corelib/concurrent/qfutureinterface.h | 313 + src/corelib/concurrent/qfutureinterface_p.h | 167 + src/corelib/concurrent/qfuturesynchronizer.cpp | 156 + src/corelib/concurrent/qfuturesynchronizer.h | 121 + src/corelib/concurrent/qfuturewatcher.cpp | 592 ++ src/corelib/concurrent/qfuturewatcher.h | 222 + src/corelib/concurrent/qfuturewatcher_p.h | 90 + src/corelib/concurrent/qrunnable.cpp | 107 + src/corelib/concurrent/qrunnable.h | 73 + src/corelib/concurrent/qtconcurrentcompilertest.h | 65 + src/corelib/concurrent/qtconcurrentexception.cpp | 223 + src/corelib/concurrent/qtconcurrentexception.h | 128 + src/corelib/concurrent/qtconcurrentfilter.cpp | 330 + src/corelib/concurrent/qtconcurrentfilter.h | 736 ++ src/corelib/concurrent/qtconcurrentfilterkernel.h | 351 + .../concurrent/qtconcurrentfunctionwrappers.h | 173 + .../concurrent/qtconcurrentiteratekernel.cpp | 199 + src/corelib/concurrent/qtconcurrentiteratekernel.h | 340 + src/corelib/concurrent/qtconcurrentmap.cpp | 402 + src/corelib/concurrent/qtconcurrentmap.h | 780 ++ src/corelib/concurrent/qtconcurrentmapkernel.h | 273 + src/corelib/concurrent/qtconcurrentmedian.h | 130 + src/corelib/concurrent/qtconcurrentreducekernel.h | 255 + src/corelib/concurrent/qtconcurrentresultstore.cpp | 256 + src/corelib/concurrent/qtconcurrentresultstore.h | 239 + src/corelib/concurrent/qtconcurrentrun.cpp | 152 + src/corelib/concurrent/qtconcurrentrun.h | 297 + src/corelib/concurrent/qtconcurrentrunbase.h | 155 + .../concurrent/qtconcurrentstoredfunctioncall.h | 1328 +++ .../concurrent/qtconcurrentthreadengine.cpp | 299 + src/corelib/concurrent/qtconcurrentthreadengine.h | 285 + src/corelib/concurrent/qthreadpool.cpp | 651 ++ src/corelib/concurrent/qthreadpool.h | 96 + src/corelib/concurrent/qthreadpool_p.h | 107 + src/corelib/corelib.pro | 48 + src/corelib/eval.pri | 4 + src/corelib/global/global.pri | 34 + src/corelib/global/qconfig-dist.h | 50 + src/corelib/global/qconfig-large.h | 173 + src/corelib/global/qconfig-medium.h | 297 + src/corelib/global/qconfig-minimal.h | 600 ++ src/corelib/global/qconfig-nacl.h | 371 + src/corelib/global/qconfig-small.h | 335 + src/corelib/global/qendian.h | 370 + src/corelib/global/qendian.qdoc | 154 + src/corelib/global/qfeatures.h | 893 ++ src/corelib/global/qfeatures.txt | 1487 +++ src/corelib/global/qglobal.cpp | 3653 ++++++++ src/corelib/global/qglobal.h | 2767 ++++++ src/corelib/global/qlibraryinfo.cpp | 555 ++ src/corelib/global/qlibraryinfo.h | 94 + src/corelib/global/qmalloc.cpp | 127 + src/corelib/global/qnamespace.h | 1882 ++++ src/corelib/global/qnamespace.qdoc | 3008 +++++++ src/corelib/global/qnumeric.cpp | 93 + src/corelib/global/qnumeric.h | 71 + src/corelib/global/qnumeric_p.h | 243 + src/corelib/global/qt_pch.h | 67 + src/corelib/global/qt_windows.h | 151 + src/corelib/io/io.pri | 119 + src/corelib/io/qabstractfileengine.cpp | 1233 +++ src/corelib/io/qabstractfileengine.h | 248 + src/corelib/io/qabstractfileengine_p.h | 81 + src/corelib/io/qbuffer.cpp | 493 + src/corelib/io/qbuffer.h | 112 + src/corelib/io/qdatastream.cpp | 1325 +++ src/corelib/io/qdatastream.h | 440 + src/corelib/io/qdatastream_p.h | 72 + src/corelib/io/qdataurl.cpp | 101 + src/corelib/io/qdataurl_p.h | 67 + src/corelib/io/qdebug.cpp | 307 + src/corelib/io/qdebug.h | 300 + src/corelib/io/qdir.cpp | 2386 +++++ src/corelib/io/qdir.h | 271 + src/corelib/io/qdir_p.h | 98 + src/corelib/io/qdiriterator.cpp | 561 ++ src/corelib/io/qdiriterator.h | 97 + src/corelib/io/qfile.cpp | 1884 ++++ src/corelib/io/qfile.h | 218 + src/corelib/io/qfile_p.h | 99 + src/corelib/io/qfileinfo.cpp | 1399 +++ src/corelib/io/qfileinfo.h | 206 + src/corelib/io/qfileinfo_p.h | 160 + src/corelib/io/qfilesystemengine.cpp | 391 + src/corelib/io/qfilesystemengine_mac.cpp | 48 + src/corelib/io/qfilesystemengine_p.h | 133 + src/corelib/io/qfilesystemengine_symbian.cpp | 408 + src/corelib/io/qfilesystemengine_unix.cpp | 660 ++ src/corelib/io/qfilesystemengine_win.cpp | 1218 +++ src/corelib/io/qfilesystementry.cpp | 383 + src/corelib/io/qfilesystementry_p.h | 126 + src/corelib/io/qfilesystemiterator_p.h | 120 + src/corelib/io/qfilesystemiterator_symbian.cpp | 127 + src/corelib/io/qfilesystemiterator_unix.cpp | 117 + src/corelib/io/qfilesystemiterator_win.cpp | 148 + src/corelib/io/qfilesystemmetadata_p.h | 400 + src/corelib/io/qfilesystemwatcher.cpp | 640 ++ src/corelib/io/qfilesystemwatcher.h | 89 + src/corelib/io/qfilesystemwatcher_dnotify.cpp | 461 + src/corelib/io/qfilesystemwatcher_dnotify_p.h | 131 + src/corelib/io/qfilesystemwatcher_fsevents.cpp | 492 + src/corelib/io/qfilesystemwatcher_fsevents_p.h | 132 + src/corelib/io/qfilesystemwatcher_inotify.cpp | 410 + src/corelib/io/qfilesystemwatcher_inotify_p.h | 95 + src/corelib/io/qfilesystemwatcher_kqueue.cpp | 334 + src/corelib/io/qfilesystemwatcher_kqueue_p.h | 97 + src/corelib/io/qfilesystemwatcher_p.h | 121 + src/corelib/io/qfilesystemwatcher_symbian.cpp | 273 + src/corelib/io/qfilesystemwatcher_symbian_p.h | 130 + src/corelib/io/qfilesystemwatcher_win.cpp | 425 + src/corelib/io/qfilesystemwatcher_win_p.h | 166 + src/corelib/io/qfsfileengine.cpp | 965 ++ src/corelib/io/qfsfileengine.h | 129 + src/corelib/io/qfsfileengine_iterator.cpp | 106 + src/corelib/io/qfsfileengine_iterator_p.h | 91 + src/corelib/io/qfsfileengine_p.h | 202 + src/corelib/io/qfsfileengine_unix.cpp | 1108 +++ src/corelib/io/qfsfileengine_win.cpp | 1008 +++ src/corelib/io/qiodevice.cpp | 1846 ++++ src/corelib/io/qiodevice.h | 254 + src/corelib/io/qiodevice_p.h | 245 + src/corelib/io/qnoncontiguousbytedevice.cpp | 545 ++ src/corelib/io/qnoncontiguousbytedevice_p.h | 190 + src/corelib/io/qprocess.cpp | 2371 +++++ src/corelib/io/qprocess.h | 245 + src/corelib/io/qprocess_p.h | 260 + src/corelib/io/qprocess_symbian.cpp | 1067 +++ src/corelib/io/qprocess_unix.cpp | 1297 +++ src/corelib/io/qprocess_win.cpp | 855 ++ src/corelib/io/qresource.cpp | 1496 +++ src/corelib/io/qresource.h | 104 + src/corelib/io/qresource_iterator.cpp | 90 + src/corelib/io/qresource_iterator_p.h | 80 + src/corelib/io/qresource_p.h | 119 + src/corelib/io/qsettings.cpp | 3843 ++++++++ src/corelib/io/qsettings.h | 313 + src/corelib/io/qsettings_mac.cpp | 654 ++ src/corelib/io/qsettings_p.h | 316 + src/corelib/io/qsettings_win.cpp | 847 ++ src/corelib/io/qtemporaryfile.cpp | 713 ++ src/corelib/io/qtemporaryfile.h | 108 + src/corelib/io/qtextstream.cpp | 3413 +++++++ src/corelib/io/qtextstream.h | 377 + src/corelib/io/qurl.cpp | 6544 ++++++++++++++ src/corelib/io/qurl.h | 302 + src/corelib/io/qwindowspipewriter.cpp | 171 + src/corelib/io/qwindowspipewriter_p.h | 162 + src/corelib/kernel/kernel.pri | 164 + src/corelib/kernel/qabstracteventdispatcher.cpp | 556 ++ src/corelib/kernel/qabstracteventdispatcher.h | 107 + src/corelib/kernel/qabstracteventdispatcher_p.h | 79 + src/corelib/kernel/qabstractitemmodel.cpp | 3454 +++++++ src/corelib/kernel/qabstractitemmodel.h | 410 + src/corelib/kernel/qabstractitemmodel_p.h | 176 + src/corelib/kernel/qbasictimer.cpp | 138 + src/corelib/kernel/qbasictimer.h | 74 + src/corelib/kernel/qcore_mac.cpp | 82 + src/corelib/kernel/qcore_mac_p.h | 163 + src/corelib/kernel/qcore_symbian_p.cpp | 317 + src/corelib/kernel/qcore_symbian_p.h | 282 + src/corelib/kernel/qcore_unix.cpp | 106 + src/corelib/kernel/qcore_unix_p.h | 333 + src/corelib/kernel/qcoreapplication.cpp | 2730 ++++++ src/corelib/kernel/qcoreapplication.h | 297 + src/corelib/kernel/qcoreapplication_mac.cpp | 66 + src/corelib/kernel/qcoreapplication_p.h | 146 + src/corelib/kernel/qcoreapplication_win.cpp | 1060 +++ src/corelib/kernel/qcorecmdlineargs_p.h | 171 + src/corelib/kernel/qcoreevent.cpp | 612 ++ src/corelib/kernel/qcoreevent.h | 396 + src/corelib/kernel/qcoreglobaldata.cpp | 53 + src/corelib/kernel/qcoreglobaldata_p.h | 72 + src/corelib/kernel/qcrashhandler.cpp | 423 + src/corelib/kernel/qcrashhandler_p.h | 81 + src/corelib/kernel/qeventdispatcher_glib.cpp | 601 ++ src/corelib/kernel/qeventdispatcher_glib_p.h | 119 + src/corelib/kernel/qeventdispatcher_symbian.cpp | 1310 +++ src/corelib/kernel/qeventdispatcher_symbian_p.h | 327 + src/corelib/kernel/qeventdispatcher_unix.cpp | 979 ++ src/corelib/kernel/qeventdispatcher_unix_p.h | 208 + src/corelib/kernel/qeventdispatcher_win.cpp | 1158 +++ src/corelib/kernel/qeventdispatcher_win_p.h | 110 + src/corelib/kernel/qeventloop.cpp | 329 + src/corelib/kernel/qeventloop.h | 101 + src/corelib/kernel/qfunctions_nacl.cpp | 156 + src/corelib/kernel/qfunctions_nacl.h | 97 + src/corelib/kernel/qfunctions_p.h | 79 + src/corelib/kernel/qfunctions_vxworks.cpp | 202 + src/corelib/kernel/qfunctions_vxworks.h | 153 + src/corelib/kernel/qfunctions_wince.cpp | 451 + src/corelib/kernel/qfunctions_wince.h | 397 + src/corelib/kernel/qmath.cpp | 305 + src/corelib/kernel/qmath.h | 288 + src/corelib/kernel/qmath.qdoc | 155 + src/corelib/kernel/qmetaobject.cpp | 2778 ++++++ src/corelib/kernel/qmetaobject.h | 242 + src/corelib/kernel/qmetaobject_p.h | 326 + src/corelib/kernel/qmetatype.cpp | 1509 ++++ src/corelib/kernel/qmetatype.h | 416 + src/corelib/kernel/qmimedata.cpp | 627 ++ src/corelib/kernel/qmimedata.h | 104 + src/corelib/kernel/qobject.cpp | 4310 +++++++++ src/corelib/kernel/qobject.h | 411 + src/corelib/kernel/qobject_p.h | 305 + src/corelib/kernel/qobjectcleanuphandler.cpp | 148 + src/corelib/kernel/qobjectcleanuphandler.h | 78 + src/corelib/kernel/qobjectdefs.h | 506 ++ src/corelib/kernel/qpointer.cpp | 270 + src/corelib/kernel/qpointer.h | 168 + src/corelib/kernel/qsharedmemory.cpp | 612 ++ src/corelib/kernel/qsharedmemory.h | 121 + src/corelib/kernel/qsharedmemory_p.h | 179 + src/corelib/kernel/qsharedmemory_symbian.cpp | 173 + src/corelib/kernel/qsharedmemory_unix.cpp | 302 + src/corelib/kernel/qsharedmemory_win.cpp | 195 + src/corelib/kernel/qsignalmapper.cpp | 321 + src/corelib/kernel/qsignalmapper.h | 100 + src/corelib/kernel/qsocketnotifier.cpp | 323 + src/corelib/kernel/qsocketnotifier.h | 93 + src/corelib/kernel/qsystemerror.cpp | 220 + src/corelib/kernel/qsystemerror_p.h | 107 + src/corelib/kernel/qsystemsemaphore.cpp | 363 + src/corelib/kernel/qsystemsemaphore.h | 103 + src/corelib/kernel/qsystemsemaphore_p.h | 118 + src/corelib/kernel/qsystemsemaphore_symbian.cpp | 138 + src/corelib/kernel/qsystemsemaphore_unix.cpp | 238 + src/corelib/kernel/qsystemsemaphore_win.cpp | 135 + src/corelib/kernel/qtcore_eval.cpp | 571 ++ src/corelib/kernel/qtimer.cpp | 394 + src/corelib/kernel/qtimer.h | 116 + src/corelib/kernel/qtranslator.cpp | 979 ++ src/corelib/kernel/qtranslator.h | 104 + src/corelib/kernel/qtranslator_p.h | 79 + src/corelib/kernel/qvariant.cpp | 3237 +++++++ src/corelib/kernel/qvariant.h | 618 ++ src/corelib/kernel/qvariant_p.h | 153 + src/corelib/kernel/qwineventnotifier_p.cpp | 134 + src/corelib/kernel/qwineventnotifier_p.h | 94 + src/corelib/plugin/plugin.pri | 35 + src/corelib/plugin/qelfparser_p.cpp | 240 + src/corelib/plugin/qelfparser_p.h | 108 + src/corelib/plugin/qfactoryinterface.h | 67 + src/corelib/plugin/qfactoryloader.cpp | 269 + src/corelib/plugin/qfactoryloader_p.h | 93 + src/corelib/plugin/qlibrary.cpp | 1295 +++ src/corelib/plugin/qlibrary.h | 120 + src/corelib/plugin/qlibrary_p.h | 124 + src/corelib/plugin/qlibrary_unix.cpp | 305 + src/corelib/plugin/qlibrary_win.cpp | 131 + src/corelib/plugin/qplugin.h | 152 + src/corelib/plugin/qplugin.qdoc | 121 + src/corelib/plugin/qpluginloader.cpp | 434 + src/corelib/plugin/qpluginloader.h | 100 + src/corelib/plugin/qsystemlibrary.cpp | 141 + src/corelib/plugin/qsystemlibrary_p.h | 110 + src/corelib/plugin/quuid.cpp | 676 ++ src/corelib/plugin/quuid.h | 190 + src/corelib/statemachine/qabstractstate.cpp | 215 + src/corelib/statemachine/qabstractstate.h | 97 + src/corelib/statemachine/qabstractstate_p.h | 95 + src/corelib/statemachine/qabstracttransition.cpp | 335 + src/corelib/statemachine/qabstracttransition.h | 118 + src/corelib/statemachine/qabstracttransition_p.h | 92 + src/corelib/statemachine/qeventtransition.cpp | 260 + src/corelib/statemachine/qeventtransition.h | 95 + src/corelib/statemachine/qeventtransition_p.h | 79 + src/corelib/statemachine/qfinalstate.cpp | 140 + src/corelib/statemachine/qfinalstate.h | 80 + src/corelib/statemachine/qhistorystate.cpp | 230 + src/corelib/statemachine/qhistorystate.h | 95 + src/corelib/statemachine/qhistorystate_p.h | 79 + src/corelib/statemachine/qsignaleventgenerator_p.h | 78 + src/corelib/statemachine/qsignaltransition.cpp | 264 + src/corelib/statemachine/qsignaltransition.h | 90 + src/corelib/statemachine/qsignaltransition_p.h | 82 + src/corelib/statemachine/qstate.cpp | 526 ++ src/corelib/statemachine/qstate.h | 122 + src/corelib/statemachine/qstate_p.h | 112 + src/corelib/statemachine/qstatemachine.cpp | 2401 +++++ src/corelib/statemachine/qstatemachine.h | 196 + src/corelib/statemachine/qstatemachine_p.h | 250 + src/corelib/statemachine/statemachine.pri | 28 + src/corelib/thread/qatomic.cpp | 1125 +++ src/corelib/thread/qatomic.h | 227 + src/corelib/thread/qbasicatomic.h | 230 + src/corelib/thread/qmutex.cpp | 515 ++ src/corelib/thread/qmutex.h | 248 + src/corelib/thread/qmutex_p.h | 107 + src/corelib/thread/qmutex_symbian.cpp | 101 + src/corelib/thread/qmutex_unix.cpp | 209 + src/corelib/thread/qmutex_win.cpp | 75 + src/corelib/thread/qmutexpool.cpp | 156 + src/corelib/thread/qmutexpool_p.h | 93 + src/corelib/thread/qorderedmutexlocker_p.h | 121 + src/corelib/thread/qreadwritelock.cpp | 581 ++ src/corelib/thread/qreadwritelock.h | 239 + src/corelib/thread/qreadwritelock_p.h | 87 + src/corelib/thread/qsemaphore.cpp | 240 + src/corelib/thread/qsemaphore.h | 83 + src/corelib/thread/qthread.cpp | 772 ++ src/corelib/thread/qthread.h | 166 + src/corelib/thread/qthread_p.h | 237 + src/corelib/thread/qthread_symbian.cpp | 609 ++ src/corelib/thread/qthread_unix.cpp | 716 ++ src/corelib/thread/qthread_win.cpp | 637 ++ src/corelib/thread/qthreadstorage.cpp | 329 + src/corelib/thread/qthreadstorage.h | 164 + src/corelib/thread/qwaitcondition.h | 105 + src/corelib/thread/qwaitcondition.qdoc | 173 + src/corelib/thread/qwaitcondition_symbian.cpp | 196 + src/corelib/thread/qwaitcondition_unix.cpp | 192 + src/corelib/thread/qwaitcondition_win.cpp | 233 + src/corelib/thread/thread.pri | 41 + src/corelib/tools/qalgorithms.h | 526 ++ src/corelib/tools/qalgorithms.qdoc | 637 ++ src/corelib/tools/qbitarray.cpp | 738 ++ src/corelib/tools/qbitarray.h | 180 + src/corelib/tools/qbytearray.cpp | 4394 +++++++++ src/corelib/tools/qbytearray.h | 622 ++ src/corelib/tools/qbytearraymatcher.cpp | 324 + src/corelib/tools/qbytearraymatcher.h | 103 + src/corelib/tools/qbytedata_p.h | 220 + src/corelib/tools/qcache.h | 217 + src/corelib/tools/qcache.qdoc | 230 + src/corelib/tools/qchar.cpp | 1654 ++++ src/corelib/tools/qchar.h | 404 + src/corelib/tools/qcontainerfwd.h | 71 + src/corelib/tools/qcontiguouscache.cpp | 474 + src/corelib/tools/qcontiguouscache.h | 466 + src/corelib/tools/qcryptographichash.cpp | 200 + src/corelib/tools/qcryptographichash.h | 84 + src/corelib/tools/qdatetime.cpp | 5881 ++++++++++++ src/corelib/tools/qdatetime.h | 340 + src/corelib/tools/qdatetime_p.h | 289 + src/corelib/tools/qeasingcurve.cpp | 937 ++ src/corelib/tools/qeasingcurve.h | 125 + src/corelib/tools/qelapsedtimer.cpp | 264 + src/corelib/tools/qelapsedtimer.h | 95 + src/corelib/tools/qelapsedtimer_generic.cpp | 194 + src/corelib/tools/qelapsedtimer_mac.cpp | 132 + src/corelib/tools/qelapsedtimer_symbian.cpp | 131 + src/corelib/tools/qelapsedtimer_unix.cpp | 209 + src/corelib/tools/qelapsedtimer_win.cpp | 183 + src/corelib/tools/qharfbuzz.cpp | 140 + src/corelib/tools/qharfbuzz_p.h | 77 + src/corelib/tools/qhash.cpp | 1914 ++++ src/corelib/tools/qhash.h | 1043 +++ src/corelib/tools/qiterator.h | 202 + src/corelib/tools/qiterator.qdoc | 1417 +++ src/corelib/tools/qline.cpp | 867 ++ src/corelib/tools/qline.h | 424 + src/corelib/tools/qlinkedlist.cpp | 1170 +++ src/corelib/tools/qlinkedlist.h | 525 ++ src/corelib/tools/qlist.cpp | 1919 ++++ src/corelib/tools/qlist.h | 900 ++ src/corelib/tools/qlocale.cpp | 3281 +++++++ src/corelib/tools/qlocale.h | 818 ++ src/corelib/tools/qlocale.qdoc | 905 ++ src/corelib/tools/qlocale_data_p.h | 6518 ++++++++++++++ src/corelib/tools/qlocale_icu.cpp | 224 + src/corelib/tools/qlocale_mac.mm | 463 + src/corelib/tools/qlocale_p.h | 283 + src/corelib/tools/qlocale_symbian.cpp | 929 ++ src/corelib/tools/qlocale_tools.cpp | 2961 ++++++ src/corelib/tools/qlocale_tools_p.h | 122 + src/corelib/tools/qlocale_unix.cpp | 226 + src/corelib/tools/qlocale_win.cpp | 988 ++ src/corelib/tools/qmap.cpp | 1646 ++++ src/corelib/tools/qmap.h | 1090 +++ src/corelib/tools/qmargins.cpp | 167 + src/corelib/tools/qmargins.h | 147 + src/corelib/tools/qpair.h | 127 + src/corelib/tools/qpair.qdoc | 215 + src/corelib/tools/qpodlist_p.h | 115 + src/corelib/tools/qpoint.cpp | 741 ++ src/corelib/tools/qpoint.h | 389 + src/corelib/tools/qqueue.cpp | 137 + src/corelib/tools/qqueue.h | 70 + src/corelib/tools/qrect.cpp | 2465 +++++ src/corelib/tools/qrect.h | 858 ++ src/corelib/tools/qregexp.cpp | 4503 ++++++++++ src/corelib/tools/qregexp.h | 169 + src/corelib/tools/qringbuffer_p.h | 451 + src/corelib/tools/qscopedpointer.cpp | 283 + src/corelib/tools/qscopedpointer.h | 245 + src/corelib/tools/qscopedpointer_p.h | 151 + src/corelib/tools/qscopedvaluerollback.cpp | 84 + src/corelib/tools/qscopedvaluerollback.h | 81 + src/corelib/tools/qset.h | 371 + src/corelib/tools/qset.qdoc | 946 ++ src/corelib/tools/qshareddata.cpp | 568 ++ src/corelib/tools/qshareddata.h | 286 + src/corelib/tools/qsharedpointer.cpp | 1501 ++++ src/corelib/tools/qsharedpointer.h | 152 + src/corelib/tools/qsharedpointer_impl.h | 898 ++ src/corelib/tools/qsimd.cpp | 413 + src/corelib/tools/qsimd_p.h | 172 + src/corelib/tools/qsize.cpp | 828 ++ src/corelib/tools/qsize.h | 368 + src/corelib/tools/qstack.cpp | 137 + src/corelib/tools/qstack.h | 83 + src/corelib/tools/qstring.cpp | 9129 +++++++++++++++++++ src/corelib/tools/qstring.h | 1295 +++ src/corelib/tools/qstringbuilder.cpp | 193 + src/corelib/tools/qstringbuilder.h | 455 + src/corelib/tools/qstringlist.cpp | 692 ++ src/corelib/tools/qstringlist.h | 262 + src/corelib/tools/qstringmatcher.cpp | 322 + src/corelib/tools/qstringmatcher.h | 103 + src/corelib/tools/qtextboundaryfinder.cpp | 479 + src/corelib/tools/qtextboundaryfinder.h | 114 + src/corelib/tools/qtimeline.cpp | 787 ++ src/corelib/tools/qtimeline.h | 147 + src/corelib/tools/qtools_p.h | 65 + src/corelib/tools/qunicodetables.cpp | 9486 ++++++++++++++++++++ src/corelib/tools/qunicodetables_p.h | 232 + src/corelib/tools/qvarlengtharray.h | 404 + src/corelib/tools/qvarlengtharray.qdoc | 547 ++ src/corelib/tools/qvector.cpp | 1017 +++ src/corelib/tools/qvector.h | 829 ++ src/corelib/tools/qvsnprintf.cpp | 133 + src/corelib/tools/tools.pri | 124 + src/corelib/xml/.gitignore | 1 + src/corelib/xml/make-parser.sh | 53 + src/corelib/xml/qxmlstream.cpp | 3954 ++++++++ src/corelib/xml/qxmlstream.g | 1847 ++++ src/corelib/xml/qxmlstream.h | 491 + src/corelib/xml/qxmlstream_p.h | 1965 ++++ src/corelib/xml/qxmlutils.cpp | 390 + src/corelib/xml/qxmlutils_p.h | 92 + src/corelib/xml/xml.pri | 10 + 556 files changed, 282993 insertions(+) create mode 100644 src/corelib/QtCore.dynlist create mode 100644 src/corelib/animation/animation.pri create mode 100644 src/corelib/animation/qabstractanimation.cpp create mode 100644 src/corelib/animation/qabstractanimation.h create mode 100644 src/corelib/animation/qabstractanimation_p.h create mode 100644 src/corelib/animation/qanimationgroup.cpp create mode 100644 src/corelib/animation/qanimationgroup.h create mode 100644 src/corelib/animation/qanimationgroup_p.h create mode 100644 src/corelib/animation/qparallelanimationgroup.cpp create mode 100644 src/corelib/animation/qparallelanimationgroup.h create mode 100644 src/corelib/animation/qparallelanimationgroup_p.h create mode 100644 src/corelib/animation/qpauseanimation.cpp create mode 100644 src/corelib/animation/qpauseanimation.h create mode 100644 src/corelib/animation/qpropertyanimation.cpp create mode 100644 src/corelib/animation/qpropertyanimation.h create mode 100644 src/corelib/animation/qpropertyanimation_p.h create mode 100644 src/corelib/animation/qsequentialanimationgroup.cpp create mode 100644 src/corelib/animation/qsequentialanimationgroup.h create mode 100644 src/corelib/animation/qsequentialanimationgroup_p.h create mode 100644 src/corelib/animation/qvariantanimation.cpp create mode 100644 src/corelib/animation/qvariantanimation.h create mode 100644 src/corelib/animation/qvariantanimation_p.h create mode 100644 src/corelib/arch/alpha/arch.pri create mode 100644 src/corelib/arch/alpha/qatomic_alpha.s create mode 100644 src/corelib/arch/arch.pri create mode 100644 src/corelib/arch/arm/arch.pri create mode 100644 src/corelib/arch/arm/qatomic_arm.cpp create mode 100644 src/corelib/arch/avr32/arch.pri create mode 100644 src/corelib/arch/bfin/arch.pri create mode 100644 src/corelib/arch/generic/arch.pri create mode 100644 src/corelib/arch/generic/qatomic_generic_unix.cpp create mode 100644 src/corelib/arch/generic/qatomic_generic_windows.cpp create mode 100644 src/corelib/arch/i386/arch.pri create mode 100644 src/corelib/arch/i386/qatomic_i386.s create mode 100644 src/corelib/arch/ia64/arch.pri create mode 100644 src/corelib/arch/ia64/qatomic_ia64.s create mode 100644 src/corelib/arch/integrity/arch.pri create mode 100644 src/corelib/arch/macosx/arch.pri create mode 100644 src/corelib/arch/macosx/qatomic32_ppc.s create mode 100644 src/corelib/arch/mips/arch.pri create mode 100644 src/corelib/arch/mips/qatomic_mips32.s create mode 100644 src/corelib/arch/mips/qatomic_mips64.s create mode 100644 src/corelib/arch/parisc/arch.pri create mode 100644 src/corelib/arch/parisc/q_ldcw.s create mode 100644 src/corelib/arch/parisc/qatomic_parisc.cpp create mode 100644 src/corelib/arch/powerpc/arch.pri create mode 100644 src/corelib/arch/powerpc/qatomic32.s create mode 100644 src/corelib/arch/powerpc/qatomic64.s create mode 100644 src/corelib/arch/qatomic_alpha.h create mode 100644 src/corelib/arch/qatomic_arch.h create mode 100644 src/corelib/arch/qatomic_arm.h create mode 100644 src/corelib/arch/qatomic_armv5.h create mode 100644 src/corelib/arch/qatomic_armv6.h create mode 100644 src/corelib/arch/qatomic_armv7.h create mode 100644 src/corelib/arch/qatomic_avr32.h create mode 100644 src/corelib/arch/qatomic_bfin.h create mode 100644 src/corelib/arch/qatomic_bootstrap.h create mode 100644 src/corelib/arch/qatomic_generic.h create mode 100644 src/corelib/arch/qatomic_i386.h create mode 100644 src/corelib/arch/qatomic_ia64.h create mode 100644 src/corelib/arch/qatomic_integrity.h create mode 100644 src/corelib/arch/qatomic_macosx.h create mode 100644 src/corelib/arch/qatomic_mips.h create mode 100644 src/corelib/arch/qatomic_parisc.h create mode 100644 src/corelib/arch/qatomic_powerpc.h create mode 100644 src/corelib/arch/qatomic_s390.h create mode 100644 src/corelib/arch/qatomic_sh.h create mode 100644 src/corelib/arch/qatomic_sh4a.h create mode 100644 src/corelib/arch/qatomic_sparc.h create mode 100644 src/corelib/arch/qatomic_symbian.h create mode 100644 src/corelib/arch/qatomic_vxworks.h create mode 100644 src/corelib/arch/qatomic_windows.h create mode 100644 src/corelib/arch/qatomic_windowsce.h create mode 100644 src/corelib/arch/qatomic_x86_64.h create mode 100644 src/corelib/arch/s390/arch.pri create mode 100644 src/corelib/arch/sh/arch.pri create mode 100644 src/corelib/arch/sh/qatomic_sh.cpp create mode 100644 src/corelib/arch/sh4a/arch.pri create mode 100644 src/corelib/arch/sparc/arch.pri create mode 100644 src/corelib/arch/sparc/qatomic32.s create mode 100644 src/corelib/arch/sparc/qatomic64.s create mode 100644 src/corelib/arch/sparc/qatomic_sparc.cpp create mode 100644 src/corelib/arch/symbian/arch.pri create mode 100644 src/corelib/arch/symbian/common_p.h create mode 100644 src/corelib/arch/symbian/debugfunction.cpp create mode 100644 src/corelib/arch/symbian/dla_p.h create mode 100644 src/corelib/arch/symbian/heap_hybrid.cpp create mode 100644 src/corelib/arch/symbian/heap_hybrid_p.h create mode 100644 src/corelib/arch/symbian/page_alloc_p.h create mode 100644 src/corelib/arch/symbian/qatomic_generic_armv6.cpp create mode 100644 src/corelib/arch/symbian/qatomic_symbian.cpp create mode 100644 src/corelib/arch/symbian/qt_heapsetup_symbian.cpp create mode 100644 src/corelib/arch/symbian/qt_hybridheap_symbian_p.h create mode 100644 src/corelib/arch/symbian/slab_p.h create mode 100644 src/corelib/arch/vxworks/arch.pri create mode 100644 src/corelib/arch/vxworks/qatomic_ppc.s create mode 100644 src/corelib/arch/windows/arch.pri create mode 100644 src/corelib/arch/x86_64/arch.pri create mode 100644 src/corelib/arch/x86_64/qatomic_sun.s create mode 100644 src/corelib/codecs/codecs.pri create mode 100644 src/corelib/codecs/codecs.qdoc create mode 100644 src/corelib/codecs/qfontlaocodec.cpp create mode 100644 src/corelib/codecs/qfontlaocodec_p.h create mode 100644 src/corelib/codecs/qiconvcodec.cpp create mode 100644 src/corelib/codecs/qiconvcodec_p.h create mode 100644 src/corelib/codecs/qisciicodec.cpp create mode 100644 src/corelib/codecs/qisciicodec_p.h create mode 100644 src/corelib/codecs/qlatincodec.cpp create mode 100644 src/corelib/codecs/qlatincodec_p.h create mode 100644 src/corelib/codecs/qsimplecodec.cpp create mode 100644 src/corelib/codecs/qsimplecodec_p.h create mode 100644 src/corelib/codecs/qtextcodec.cpp create mode 100644 src/corelib/codecs/qtextcodec.h create mode 100644 src/corelib/codecs/qtextcodec_p.h create mode 100644 src/corelib/codecs/qtextcodec_symbian.cpp create mode 100644 src/corelib/codecs/qtextcodecplugin.cpp create mode 100644 src/corelib/codecs/qtextcodecplugin.h create mode 100644 src/corelib/codecs/qtsciicodec.cpp create mode 100644 src/corelib/codecs/qtsciicodec_p.h create mode 100644 src/corelib/codecs/qutfcodec.cpp create mode 100644 src/corelib/codecs/qutfcodec_p.h create mode 100644 src/corelib/concurrent/concurrent.pri create mode 100644 src/corelib/concurrent/qfuture.cpp create mode 100644 src/corelib/concurrent/qfuture.h create mode 100644 src/corelib/concurrent/qfutureinterface.cpp create mode 100644 src/corelib/concurrent/qfutureinterface.h create mode 100644 src/corelib/concurrent/qfutureinterface_p.h create mode 100644 src/corelib/concurrent/qfuturesynchronizer.cpp create mode 100644 src/corelib/concurrent/qfuturesynchronizer.h create mode 100644 src/corelib/concurrent/qfuturewatcher.cpp create mode 100644 src/corelib/concurrent/qfuturewatcher.h create mode 100644 src/corelib/concurrent/qfuturewatcher_p.h create mode 100644 src/corelib/concurrent/qrunnable.cpp create mode 100644 src/corelib/concurrent/qrunnable.h create mode 100644 src/corelib/concurrent/qtconcurrentcompilertest.h create mode 100644 src/corelib/concurrent/qtconcurrentexception.cpp create mode 100644 src/corelib/concurrent/qtconcurrentexception.h create mode 100644 src/corelib/concurrent/qtconcurrentfilter.cpp create mode 100644 src/corelib/concurrent/qtconcurrentfilter.h create mode 100644 src/corelib/concurrent/qtconcurrentfilterkernel.h create mode 100644 src/corelib/concurrent/qtconcurrentfunctionwrappers.h create mode 100644 src/corelib/concurrent/qtconcurrentiteratekernel.cpp create mode 100644 src/corelib/concurrent/qtconcurrentiteratekernel.h create mode 100644 src/corelib/concurrent/qtconcurrentmap.cpp create mode 100644 src/corelib/concurrent/qtconcurrentmap.h create mode 100644 src/corelib/concurrent/qtconcurrentmapkernel.h create mode 100644 src/corelib/concurrent/qtconcurrentmedian.h create mode 100644 src/corelib/concurrent/qtconcurrentreducekernel.h create mode 100644 src/corelib/concurrent/qtconcurrentresultstore.cpp create mode 100644 src/corelib/concurrent/qtconcurrentresultstore.h create mode 100644 src/corelib/concurrent/qtconcurrentrun.cpp create mode 100644 src/corelib/concurrent/qtconcurrentrun.h create mode 100644 src/corelib/concurrent/qtconcurrentrunbase.h create mode 100644 src/corelib/concurrent/qtconcurrentstoredfunctioncall.h create mode 100644 src/corelib/concurrent/qtconcurrentthreadengine.cpp create mode 100644 src/corelib/concurrent/qtconcurrentthreadengine.h create mode 100644 src/corelib/concurrent/qthreadpool.cpp create mode 100644 src/corelib/concurrent/qthreadpool.h create mode 100644 src/corelib/concurrent/qthreadpool_p.h create mode 100644 src/corelib/corelib.pro create mode 100644 src/corelib/eval.pri create mode 100644 src/corelib/global/global.pri create mode 100644 src/corelib/global/qconfig-dist.h create mode 100644 src/corelib/global/qconfig-large.h create mode 100644 src/corelib/global/qconfig-medium.h create mode 100644 src/corelib/global/qconfig-minimal.h create mode 100644 src/corelib/global/qconfig-nacl.h create mode 100644 src/corelib/global/qconfig-small.h create mode 100644 src/corelib/global/qendian.h create mode 100644 src/corelib/global/qendian.qdoc create mode 100644 src/corelib/global/qfeatures.h create mode 100644 src/corelib/global/qfeatures.txt create mode 100644 src/corelib/global/qglobal.cpp create mode 100644 src/corelib/global/qglobal.h create mode 100644 src/corelib/global/qlibraryinfo.cpp create mode 100644 src/corelib/global/qlibraryinfo.h create mode 100644 src/corelib/global/qmalloc.cpp create mode 100644 src/corelib/global/qnamespace.h create mode 100644 src/corelib/global/qnamespace.qdoc create mode 100644 src/corelib/global/qnumeric.cpp create mode 100644 src/corelib/global/qnumeric.h create mode 100644 src/corelib/global/qnumeric_p.h create mode 100644 src/corelib/global/qt_pch.h create mode 100644 src/corelib/global/qt_windows.h create mode 100644 src/corelib/io/io.pri create mode 100644 src/corelib/io/qabstractfileengine.cpp create mode 100644 src/corelib/io/qabstractfileengine.h create mode 100644 src/corelib/io/qabstractfileengine_p.h create mode 100644 src/corelib/io/qbuffer.cpp create mode 100644 src/corelib/io/qbuffer.h create mode 100644 src/corelib/io/qdatastream.cpp create mode 100644 src/corelib/io/qdatastream.h create mode 100644 src/corelib/io/qdatastream_p.h create mode 100644 src/corelib/io/qdataurl.cpp create mode 100644 src/corelib/io/qdataurl_p.h create mode 100644 src/corelib/io/qdebug.cpp create mode 100644 src/corelib/io/qdebug.h create mode 100644 src/corelib/io/qdir.cpp create mode 100644 src/corelib/io/qdir.h create mode 100644 src/corelib/io/qdir_p.h create mode 100644 src/corelib/io/qdiriterator.cpp create mode 100644 src/corelib/io/qdiriterator.h create mode 100644 src/corelib/io/qfile.cpp create mode 100644 src/corelib/io/qfile.h create mode 100644 src/corelib/io/qfile_p.h create mode 100644 src/corelib/io/qfileinfo.cpp create mode 100644 src/corelib/io/qfileinfo.h create mode 100644 src/corelib/io/qfileinfo_p.h create mode 100644 src/corelib/io/qfilesystemengine.cpp create mode 100644 src/corelib/io/qfilesystemengine_mac.cpp create mode 100644 src/corelib/io/qfilesystemengine_p.h create mode 100644 src/corelib/io/qfilesystemengine_symbian.cpp create mode 100644 src/corelib/io/qfilesystemengine_unix.cpp create mode 100644 src/corelib/io/qfilesystemengine_win.cpp create mode 100644 src/corelib/io/qfilesystementry.cpp create mode 100644 src/corelib/io/qfilesystementry_p.h create mode 100644 src/corelib/io/qfilesystemiterator_p.h create mode 100644 src/corelib/io/qfilesystemiterator_symbian.cpp create mode 100644 src/corelib/io/qfilesystemiterator_unix.cpp create mode 100644 src/corelib/io/qfilesystemiterator_win.cpp create mode 100644 src/corelib/io/qfilesystemmetadata_p.h create mode 100644 src/corelib/io/qfilesystemwatcher.cpp create mode 100644 src/corelib/io/qfilesystemwatcher.h create mode 100644 src/corelib/io/qfilesystemwatcher_dnotify.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_dnotify_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_fsevents.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_fsevents_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_inotify.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_inotify_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_kqueue.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_kqueue_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_symbian.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_symbian_p.h create mode 100644 src/corelib/io/qfilesystemwatcher_win.cpp create mode 100644 src/corelib/io/qfilesystemwatcher_win_p.h create mode 100644 src/corelib/io/qfsfileengine.cpp create mode 100644 src/corelib/io/qfsfileengine.h create mode 100644 src/corelib/io/qfsfileengine_iterator.cpp create mode 100644 src/corelib/io/qfsfileengine_iterator_p.h create mode 100644 src/corelib/io/qfsfileengine_p.h create mode 100644 src/corelib/io/qfsfileengine_unix.cpp create mode 100644 src/corelib/io/qfsfileengine_win.cpp create mode 100644 src/corelib/io/qiodevice.cpp create mode 100644 src/corelib/io/qiodevice.h create mode 100644 src/corelib/io/qiodevice_p.h create mode 100644 src/corelib/io/qnoncontiguousbytedevice.cpp create mode 100644 src/corelib/io/qnoncontiguousbytedevice_p.h create mode 100644 src/corelib/io/qprocess.cpp create mode 100644 src/corelib/io/qprocess.h create mode 100644 src/corelib/io/qprocess_p.h create mode 100644 src/corelib/io/qprocess_symbian.cpp create mode 100644 src/corelib/io/qprocess_unix.cpp create mode 100644 src/corelib/io/qprocess_win.cpp create mode 100644 src/corelib/io/qresource.cpp create mode 100644 src/corelib/io/qresource.h create mode 100644 src/corelib/io/qresource_iterator.cpp create mode 100644 src/corelib/io/qresource_iterator_p.h create mode 100644 src/corelib/io/qresource_p.h create mode 100644 src/corelib/io/qsettings.cpp create mode 100644 src/corelib/io/qsettings.h create mode 100644 src/corelib/io/qsettings_mac.cpp create mode 100644 src/corelib/io/qsettings_p.h create mode 100644 src/corelib/io/qsettings_win.cpp create mode 100644 src/corelib/io/qtemporaryfile.cpp create mode 100644 src/corelib/io/qtemporaryfile.h create mode 100644 src/corelib/io/qtextstream.cpp create mode 100644 src/corelib/io/qtextstream.h create mode 100644 src/corelib/io/qurl.cpp create mode 100644 src/corelib/io/qurl.h create mode 100644 src/corelib/io/qwindowspipewriter.cpp create mode 100644 src/corelib/io/qwindowspipewriter_p.h create mode 100644 src/corelib/kernel/kernel.pri create mode 100644 src/corelib/kernel/qabstracteventdispatcher.cpp create mode 100644 src/corelib/kernel/qabstracteventdispatcher.h create mode 100644 src/corelib/kernel/qabstracteventdispatcher_p.h create mode 100644 src/corelib/kernel/qabstractitemmodel.cpp create mode 100644 src/corelib/kernel/qabstractitemmodel.h create mode 100644 src/corelib/kernel/qabstractitemmodel_p.h create mode 100644 src/corelib/kernel/qbasictimer.cpp create mode 100644 src/corelib/kernel/qbasictimer.h create mode 100644 src/corelib/kernel/qcore_mac.cpp create mode 100644 src/corelib/kernel/qcore_mac_p.h create mode 100644 src/corelib/kernel/qcore_symbian_p.cpp create mode 100644 src/corelib/kernel/qcore_symbian_p.h create mode 100644 src/corelib/kernel/qcore_unix.cpp create mode 100644 src/corelib/kernel/qcore_unix_p.h create mode 100644 src/corelib/kernel/qcoreapplication.cpp create mode 100644 src/corelib/kernel/qcoreapplication.h create mode 100644 src/corelib/kernel/qcoreapplication_mac.cpp create mode 100644 src/corelib/kernel/qcoreapplication_p.h create mode 100644 src/corelib/kernel/qcoreapplication_win.cpp create mode 100644 src/corelib/kernel/qcorecmdlineargs_p.h create mode 100644 src/corelib/kernel/qcoreevent.cpp create mode 100644 src/corelib/kernel/qcoreevent.h create mode 100644 src/corelib/kernel/qcoreglobaldata.cpp create mode 100644 src/corelib/kernel/qcoreglobaldata_p.h create mode 100644 src/corelib/kernel/qcrashhandler.cpp create mode 100644 src/corelib/kernel/qcrashhandler_p.h create mode 100644 src/corelib/kernel/qeventdispatcher_glib.cpp create mode 100644 src/corelib/kernel/qeventdispatcher_glib_p.h create mode 100644 src/corelib/kernel/qeventdispatcher_symbian.cpp create mode 100644 src/corelib/kernel/qeventdispatcher_symbian_p.h create mode 100644 src/corelib/kernel/qeventdispatcher_unix.cpp create mode 100644 src/corelib/kernel/qeventdispatcher_unix_p.h create mode 100644 src/corelib/kernel/qeventdispatcher_win.cpp create mode 100644 src/corelib/kernel/qeventdispatcher_win_p.h create mode 100644 src/corelib/kernel/qeventloop.cpp create mode 100644 src/corelib/kernel/qeventloop.h create mode 100644 src/corelib/kernel/qfunctions_nacl.cpp create mode 100644 src/corelib/kernel/qfunctions_nacl.h create mode 100644 src/corelib/kernel/qfunctions_p.h create mode 100644 src/corelib/kernel/qfunctions_vxworks.cpp create mode 100644 src/corelib/kernel/qfunctions_vxworks.h create mode 100644 src/corelib/kernel/qfunctions_wince.cpp create mode 100644 src/corelib/kernel/qfunctions_wince.h create mode 100644 src/corelib/kernel/qmath.cpp create mode 100644 src/corelib/kernel/qmath.h create mode 100644 src/corelib/kernel/qmath.qdoc create mode 100644 src/corelib/kernel/qmetaobject.cpp create mode 100644 src/corelib/kernel/qmetaobject.h create mode 100644 src/corelib/kernel/qmetaobject_p.h create mode 100644 src/corelib/kernel/qmetatype.cpp create mode 100644 src/corelib/kernel/qmetatype.h create mode 100644 src/corelib/kernel/qmimedata.cpp create mode 100644 src/corelib/kernel/qmimedata.h create mode 100644 src/corelib/kernel/qobject.cpp create mode 100644 src/corelib/kernel/qobject.h create mode 100644 src/corelib/kernel/qobject_p.h create mode 100644 src/corelib/kernel/qobjectcleanuphandler.cpp create mode 100644 src/corelib/kernel/qobjectcleanuphandler.h create mode 100644 src/corelib/kernel/qobjectdefs.h create mode 100644 src/corelib/kernel/qpointer.cpp create mode 100644 src/corelib/kernel/qpointer.h create mode 100644 src/corelib/kernel/qsharedmemory.cpp create mode 100644 src/corelib/kernel/qsharedmemory.h create mode 100644 src/corelib/kernel/qsharedmemory_p.h create mode 100644 src/corelib/kernel/qsharedmemory_symbian.cpp create mode 100644 src/corelib/kernel/qsharedmemory_unix.cpp create mode 100644 src/corelib/kernel/qsharedmemory_win.cpp create mode 100644 src/corelib/kernel/qsignalmapper.cpp create mode 100644 src/corelib/kernel/qsignalmapper.h create mode 100644 src/corelib/kernel/qsocketnotifier.cpp create mode 100644 src/corelib/kernel/qsocketnotifier.h create mode 100644 src/corelib/kernel/qsystemerror.cpp create mode 100644 src/corelib/kernel/qsystemerror_p.h create mode 100644 src/corelib/kernel/qsystemsemaphore.cpp create mode 100644 src/corelib/kernel/qsystemsemaphore.h create mode 100644 src/corelib/kernel/qsystemsemaphore_p.h create mode 100644 src/corelib/kernel/qsystemsemaphore_symbian.cpp create mode 100644 src/corelib/kernel/qsystemsemaphore_unix.cpp create mode 100644 src/corelib/kernel/qsystemsemaphore_win.cpp create mode 100644 src/corelib/kernel/qtcore_eval.cpp create mode 100644 src/corelib/kernel/qtimer.cpp create mode 100644 src/corelib/kernel/qtimer.h create mode 100644 src/corelib/kernel/qtranslator.cpp create mode 100644 src/corelib/kernel/qtranslator.h create mode 100644 src/corelib/kernel/qtranslator_p.h create mode 100644 src/corelib/kernel/qvariant.cpp create mode 100644 src/corelib/kernel/qvariant.h create mode 100644 src/corelib/kernel/qvariant_p.h create mode 100644 src/corelib/kernel/qwineventnotifier_p.cpp create mode 100644 src/corelib/kernel/qwineventnotifier_p.h create mode 100644 src/corelib/plugin/plugin.pri create mode 100644 src/corelib/plugin/qelfparser_p.cpp create mode 100644 src/corelib/plugin/qelfparser_p.h create mode 100644 src/corelib/plugin/qfactoryinterface.h create mode 100644 src/corelib/plugin/qfactoryloader.cpp create mode 100644 src/corelib/plugin/qfactoryloader_p.h create mode 100644 src/corelib/plugin/qlibrary.cpp create mode 100644 src/corelib/plugin/qlibrary.h create mode 100644 src/corelib/plugin/qlibrary_p.h create mode 100644 src/corelib/plugin/qlibrary_unix.cpp create mode 100644 src/corelib/plugin/qlibrary_win.cpp create mode 100644 src/corelib/plugin/qplugin.h create mode 100644 src/corelib/plugin/qplugin.qdoc create mode 100644 src/corelib/plugin/qpluginloader.cpp create mode 100644 src/corelib/plugin/qpluginloader.h create mode 100644 src/corelib/plugin/qsystemlibrary.cpp create mode 100644 src/corelib/plugin/qsystemlibrary_p.h create mode 100644 src/corelib/plugin/quuid.cpp create mode 100644 src/corelib/plugin/quuid.h create mode 100644 src/corelib/statemachine/qabstractstate.cpp create mode 100644 src/corelib/statemachine/qabstractstate.h create mode 100644 src/corelib/statemachine/qabstractstate_p.h create mode 100644 src/corelib/statemachine/qabstracttransition.cpp create mode 100644 src/corelib/statemachine/qabstracttransition.h create mode 100644 src/corelib/statemachine/qabstracttransition_p.h create mode 100644 src/corelib/statemachine/qeventtransition.cpp create mode 100644 src/corelib/statemachine/qeventtransition.h create mode 100644 src/corelib/statemachine/qeventtransition_p.h create mode 100644 src/corelib/statemachine/qfinalstate.cpp create mode 100644 src/corelib/statemachine/qfinalstate.h create mode 100644 src/corelib/statemachine/qhistorystate.cpp create mode 100644 src/corelib/statemachine/qhistorystate.h create mode 100644 src/corelib/statemachine/qhistorystate_p.h create mode 100644 src/corelib/statemachine/qsignaleventgenerator_p.h create mode 100644 src/corelib/statemachine/qsignaltransition.cpp create mode 100644 src/corelib/statemachine/qsignaltransition.h create mode 100644 src/corelib/statemachine/qsignaltransition_p.h create mode 100644 src/corelib/statemachine/qstate.cpp create mode 100644 src/corelib/statemachine/qstate.h create mode 100644 src/corelib/statemachine/qstate_p.h create mode 100644 src/corelib/statemachine/qstatemachine.cpp create mode 100644 src/corelib/statemachine/qstatemachine.h create mode 100644 src/corelib/statemachine/qstatemachine_p.h create mode 100644 src/corelib/statemachine/statemachine.pri create mode 100644 src/corelib/thread/qatomic.cpp create mode 100644 src/corelib/thread/qatomic.h create mode 100644 src/corelib/thread/qbasicatomic.h create mode 100644 src/corelib/thread/qmutex.cpp create mode 100644 src/corelib/thread/qmutex.h create mode 100644 src/corelib/thread/qmutex_p.h create mode 100644 src/corelib/thread/qmutex_symbian.cpp create mode 100644 src/corelib/thread/qmutex_unix.cpp create mode 100644 src/corelib/thread/qmutex_win.cpp create mode 100644 src/corelib/thread/qmutexpool.cpp create mode 100644 src/corelib/thread/qmutexpool_p.h create mode 100644 src/corelib/thread/qorderedmutexlocker_p.h create mode 100644 src/corelib/thread/qreadwritelock.cpp create mode 100644 src/corelib/thread/qreadwritelock.h create mode 100644 src/corelib/thread/qreadwritelock_p.h create mode 100644 src/corelib/thread/qsemaphore.cpp create mode 100644 src/corelib/thread/qsemaphore.h create mode 100644 src/corelib/thread/qthread.cpp create mode 100644 src/corelib/thread/qthread.h create mode 100644 src/corelib/thread/qthread_p.h create mode 100644 src/corelib/thread/qthread_symbian.cpp create mode 100644 src/corelib/thread/qthread_unix.cpp create mode 100644 src/corelib/thread/qthread_win.cpp create mode 100644 src/corelib/thread/qthreadstorage.cpp create mode 100644 src/corelib/thread/qthreadstorage.h create mode 100644 src/corelib/thread/qwaitcondition.h create mode 100644 src/corelib/thread/qwaitcondition.qdoc create mode 100644 src/corelib/thread/qwaitcondition_symbian.cpp create mode 100644 src/corelib/thread/qwaitcondition_unix.cpp create mode 100644 src/corelib/thread/qwaitcondition_win.cpp create mode 100644 src/corelib/thread/thread.pri create mode 100644 src/corelib/tools/qalgorithms.h create mode 100644 src/corelib/tools/qalgorithms.qdoc create mode 100644 src/corelib/tools/qbitarray.cpp create mode 100644 src/corelib/tools/qbitarray.h create mode 100644 src/corelib/tools/qbytearray.cpp create mode 100644 src/corelib/tools/qbytearray.h create mode 100644 src/corelib/tools/qbytearraymatcher.cpp create mode 100644 src/corelib/tools/qbytearraymatcher.h create mode 100644 src/corelib/tools/qbytedata_p.h create mode 100644 src/corelib/tools/qcache.h create mode 100644 src/corelib/tools/qcache.qdoc create mode 100644 src/corelib/tools/qchar.cpp create mode 100644 src/corelib/tools/qchar.h create mode 100644 src/corelib/tools/qcontainerfwd.h create mode 100644 src/corelib/tools/qcontiguouscache.cpp create mode 100644 src/corelib/tools/qcontiguouscache.h create mode 100644 src/corelib/tools/qcryptographichash.cpp create mode 100644 src/corelib/tools/qcryptographichash.h create mode 100644 src/corelib/tools/qdatetime.cpp create mode 100644 src/corelib/tools/qdatetime.h create mode 100644 src/corelib/tools/qdatetime_p.h create mode 100644 src/corelib/tools/qeasingcurve.cpp create mode 100644 src/corelib/tools/qeasingcurve.h create mode 100644 src/corelib/tools/qelapsedtimer.cpp create mode 100644 src/corelib/tools/qelapsedtimer.h create mode 100644 src/corelib/tools/qelapsedtimer_generic.cpp create mode 100644 src/corelib/tools/qelapsedtimer_mac.cpp create mode 100644 src/corelib/tools/qelapsedtimer_symbian.cpp create mode 100644 src/corelib/tools/qelapsedtimer_unix.cpp create mode 100644 src/corelib/tools/qelapsedtimer_win.cpp create mode 100644 src/corelib/tools/qharfbuzz.cpp create mode 100644 src/corelib/tools/qharfbuzz_p.h create mode 100644 src/corelib/tools/qhash.cpp create mode 100644 src/corelib/tools/qhash.h create mode 100644 src/corelib/tools/qiterator.h create mode 100644 src/corelib/tools/qiterator.qdoc create mode 100644 src/corelib/tools/qline.cpp create mode 100644 src/corelib/tools/qline.h create mode 100644 src/corelib/tools/qlinkedlist.cpp create mode 100644 src/corelib/tools/qlinkedlist.h create mode 100644 src/corelib/tools/qlist.cpp create mode 100644 src/corelib/tools/qlist.h create mode 100644 src/corelib/tools/qlocale.cpp create mode 100644 src/corelib/tools/qlocale.h create mode 100644 src/corelib/tools/qlocale.qdoc create mode 100644 src/corelib/tools/qlocale_data_p.h create mode 100644 src/corelib/tools/qlocale_icu.cpp create mode 100644 src/corelib/tools/qlocale_mac.mm create mode 100644 src/corelib/tools/qlocale_p.h create mode 100644 src/corelib/tools/qlocale_symbian.cpp create mode 100644 src/corelib/tools/qlocale_tools.cpp create mode 100644 src/corelib/tools/qlocale_tools_p.h create mode 100644 src/corelib/tools/qlocale_unix.cpp create mode 100644 src/corelib/tools/qlocale_win.cpp create mode 100644 src/corelib/tools/qmap.cpp create mode 100644 src/corelib/tools/qmap.h create mode 100644 src/corelib/tools/qmargins.cpp create mode 100644 src/corelib/tools/qmargins.h create mode 100644 src/corelib/tools/qpair.h create mode 100644 src/corelib/tools/qpair.qdoc create mode 100644 src/corelib/tools/qpodlist_p.h create mode 100644 src/corelib/tools/qpoint.cpp create mode 100644 src/corelib/tools/qpoint.h create mode 100644 src/corelib/tools/qqueue.cpp create mode 100644 src/corelib/tools/qqueue.h create mode 100644 src/corelib/tools/qrect.cpp create mode 100644 src/corelib/tools/qrect.h create mode 100644 src/corelib/tools/qregexp.cpp create mode 100644 src/corelib/tools/qregexp.h create mode 100644 src/corelib/tools/qringbuffer_p.h create mode 100644 src/corelib/tools/qscopedpointer.cpp create mode 100644 src/corelib/tools/qscopedpointer.h create mode 100644 src/corelib/tools/qscopedpointer_p.h create mode 100644 src/corelib/tools/qscopedvaluerollback.cpp create mode 100644 src/corelib/tools/qscopedvaluerollback.h create mode 100644 src/corelib/tools/qset.h create mode 100644 src/corelib/tools/qset.qdoc create mode 100644 src/corelib/tools/qshareddata.cpp create mode 100644 src/corelib/tools/qshareddata.h create mode 100644 src/corelib/tools/qsharedpointer.cpp create mode 100644 src/corelib/tools/qsharedpointer.h create mode 100644 src/corelib/tools/qsharedpointer_impl.h create mode 100644 src/corelib/tools/qsimd.cpp create mode 100644 src/corelib/tools/qsimd_p.h create mode 100644 src/corelib/tools/qsize.cpp create mode 100644 src/corelib/tools/qsize.h create mode 100644 src/corelib/tools/qstack.cpp create mode 100644 src/corelib/tools/qstack.h create mode 100644 src/corelib/tools/qstring.cpp create mode 100644 src/corelib/tools/qstring.h create mode 100644 src/corelib/tools/qstringbuilder.cpp create mode 100644 src/corelib/tools/qstringbuilder.h create mode 100644 src/corelib/tools/qstringlist.cpp create mode 100644 src/corelib/tools/qstringlist.h create mode 100644 src/corelib/tools/qstringmatcher.cpp create mode 100644 src/corelib/tools/qstringmatcher.h create mode 100644 src/corelib/tools/qtextboundaryfinder.cpp create mode 100644 src/corelib/tools/qtextboundaryfinder.h create mode 100644 src/corelib/tools/qtimeline.cpp create mode 100644 src/corelib/tools/qtimeline.h create mode 100644 src/corelib/tools/qtools_p.h create mode 100644 src/corelib/tools/qunicodetables.cpp create mode 100644 src/corelib/tools/qunicodetables_p.h create mode 100644 src/corelib/tools/qvarlengtharray.h create mode 100644 src/corelib/tools/qvarlengtharray.qdoc create mode 100644 src/corelib/tools/qvector.cpp create mode 100644 src/corelib/tools/qvector.h create mode 100644 src/corelib/tools/qvsnprintf.cpp create mode 100644 src/corelib/tools/tools.pri create mode 100644 src/corelib/xml/.gitignore create mode 100755 src/corelib/xml/make-parser.sh create mode 100644 src/corelib/xml/qxmlstream.cpp create mode 100644 src/corelib/xml/qxmlstream.g create mode 100644 src/corelib/xml/qxmlstream.h create mode 100644 src/corelib/xml/qxmlstream_p.h create mode 100644 src/corelib/xml/qxmlutils.cpp create mode 100644 src/corelib/xml/qxmlutils_p.h create mode 100644 src/corelib/xml/xml.pri (limited to 'src/corelib') diff --git a/src/corelib/QtCore.dynlist b/src/corelib/QtCore.dynlist new file mode 100644 index 0000000000..51e4c5a34e --- /dev/null +++ b/src/corelib/QtCore.dynlist @@ -0,0 +1,10 @@ +{ + extern "C" { + "qt_startup_hook"; + "qt_addObject"; + "qt_removeObject"; + }; + extern "C++" { + "QEventLoop::exec(QFlags)"; + }; +}; diff --git a/src/corelib/animation/animation.pri b/src/corelib/animation/animation.pri new file mode 100644 index 0000000000..cb7850c7d6 --- /dev/null +++ b/src/corelib/animation/animation.pri @@ -0,0 +1,25 @@ +# Qt core animation module + +HEADERS += \ + animation/qabstractanimation.h \ + animation/qabstractanimation_p.h \ + animation/qvariantanimation.h \ + animation/qvariantanimation_p.h \ + animation/qpropertyanimation.h \ + animation/qpropertyanimation_p.h \ + animation/qanimationgroup.h \ + animation/qanimationgroup_p.h \ + animation/qsequentialanimationgroup.h \ + animation/qsequentialanimationgroup_p.h \ + animation/qparallelanimationgroup.h \ + animation/qparallelanimationgroup_p.h \ + animation/qpauseanimation.h + +SOURCES += \ + animation/qabstractanimation.cpp \ + animation/qvariantanimation.cpp \ + animation/qpropertyanimation.cpp \ + animation/qanimationgroup.cpp \ + animation/qsequentialanimationgroup.cpp \ + animation/qparallelanimationgroup.cpp \ + animation/qpauseanimation.cpp diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp new file mode 100644 index 0000000000..602cf8a6fd --- /dev/null +++ b/src/corelib/animation/qabstractanimation.cpp @@ -0,0 +1,1055 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QAbstractAnimation + \ingroup animation + \brief The QAbstractAnimation class is the base of all animations. + \since 4.6 + + The class defines the functions for the functionality shared by + all animations. By inheriting this class, you can create custom + animations that plug into the rest of the animation framework. + + The progress of an animation is given by its current time + (currentLoopTime()), which is measured in milliseconds from the start + of the animation (0) to its end (duration()). The value is updated + automatically while the animation is running. It can also be set + directly with setCurrentTime(). + + At any point an animation is in one of three states: + \l{QAbstractAnimation::}{Running}, + \l{QAbstractAnimation::}{Stopped}, or + \l{QAbstractAnimation::}{Paused}--as defined by the + \l{QAbstractAnimation::}{State} enum. The current state can be + changed by calling start(), stop(), pause(), or resume(). An + animation will always reset its \l{currentTime()}{current time} + when it is started. If paused, it will continue with the same + current time when resumed. When an animation is stopped, it cannot + be resumed, but will keep its current time (until started again). + QAbstractAnimation will emit stateChanged() whenever its state + changes. + + An animation can loop any number of times by setting the loopCount + property. When an animation's current time reaches its duration(), + it will reset the current time and keep running. A loop count of 1 + (the default value) means that the animation will run one time. + Note that a duration of -1 means that the animation will run until + stopped; the current time will increase indefinitely. When the + current time equals duration() and the animation is in its + final loop, the \l{QAbstractAnimation::}{Stopped} state is + entered, and the finished() signal is emitted. + + QAbstractAnimation provides pure virtual functions used by + subclasses to track the progress of the animation: duration() and + updateCurrentTime(). The duration() function lets you report a + duration for the animation (as discussed above). The animation + framework calls updateCurrentTime() when current time has changed. + By reimplementing this function, you can track the animation + progress. Note that neither the interval between calls nor the + number of calls to this function are defined; though, it will + normally be 60 updates per second. + + By reimplementing updateState(), you can track the animation's + state changes, which is particularly useful for animations that + are not driven by time. + + \sa QVariantAnimation, QPropertyAnimation, QAnimationGroup, {The Animation Framework} +*/ + +/*! + \enum QAbstractAnimation::DeletionPolicy + + \value KeepWhenStopped The animation will not be deleted when stopped. + \value DeleteWhenStopped The animation will be automatically deleted when + stopped. +*/ + +/*! + \fn QAbstractAnimation::finished() + + QAbstractAnimation emits this signal after the animation has stopped and + has reached the end. + + This signal is emitted after stateChanged(). + + \sa stateChanged() +*/ + +/*! + \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) + + QAbstractAnimation emits this signal whenever the state of the animation has + changed from \a oldState to \a newState. This signal is emitted after the virtual + updateState() function is called. + + \sa updateState() +*/ + +/*! + \fn QAbstractAnimation::currentLoopChanged(int currentLoop) + + QAbstractAnimation emits this signal whenever the current loop + changes. \a currentLoop is the current loop. + + \sa currentLoop(), loopCount() +*/ + +/*! + \fn QAbstractAnimation::directionChanged(QAbstractAnimation::Direction newDirection); + + QAbstractAnimation emits this signal whenever the direction has been + changed. \a newDirection is the new direction. + + \sa direction +*/ + +#include "qabstractanimation.h" +#include "qanimationgroup.h" + +#include + +#include "qabstractanimation_p.h" + +#include +#include +#include +#include + +#ifndef QT_NO_ANIMATION + +#define DEFAULT_TIMER_INTERVAL 16 +#define STARTSTOP_TIMER_DELAY 0 + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_THREAD +Q_GLOBAL_STATIC(QThreadStorage, unifiedTimer) +#endif + +QUnifiedTimer::QUnifiedTimer() : + QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), + currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false), + slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0) +{ + time.invalidate(); + driver = &defaultDriver; +} + + +QUnifiedTimer *QUnifiedTimer::instance(bool create) +{ + QUnifiedTimer *inst; +#ifndef QT_NO_THREAD + if (create && !unifiedTimer()->hasLocalData()) { + inst = new QUnifiedTimer; + unifiedTimer()->setLocalData(inst); + } else { + inst = unifiedTimer()->localData(); + } +#else + static QUnifiedTimer unifiedTimer; + inst = &unifiedTimer; +#endif + return inst; +} + +QUnifiedTimer *QUnifiedTimer::instance() +{ + return instance(true); +} + +void QUnifiedTimer::ensureTimerUpdate() +{ + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst && inst->isPauseTimerActive) + inst->updateAnimationsTime(); +} + +void QUnifiedTimer::updateAnimationsTime() +{ + //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations + if(insideTick) + return; + + qint64 totalElapsed = time.elapsed(); + // ignore consistentTiming in case the pause timer is active + int delta = (consistentTiming && !isPauseTimerActive) ? + timingInterval : totalElapsed - lastTick; + if (slowMode) { + if (slowdownFactor > 0) + delta = qRound(delta / slowdownFactor); + else + delta = 0; + } + + lastTick = totalElapsed; + + //we make sure we only call update time if the time has actually changed + //it might happen in some cases that the time doesn't change because events are delayed + //when the CPU load is high + if (delta) { + insideTick = true; + for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { + QAbstractAnimation *animation = animations.at(currentAnimationIdx); + int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime + + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); + animation->setCurrentTime(elapsed); + } + insideTick = false; + currentAnimationIdx = 0; + } +} + +void QUnifiedTimer::updateAnimationTimer() +{ + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst) + inst->restartAnimationTimer(); +} + +void QUnifiedTimer::restartAnimationTimer() +{ + if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { + int closestTimeToFinish = closestPauseAnimationTimeToFinish(); + if (closestTimeToFinish < 0) { + qDebug() << runningPauseAnimations; + qDebug() << closestPauseAnimationTimeToFinish(); + } + driver->stop(); + animationTimer.start(closestTimeToFinish, this); + isPauseTimerActive = true; + } else if (!driver->isRunning() || isPauseTimerActive) { + driver->start(); + isPauseTimerActive = false; + } +} + +void QUnifiedTimer::setTimingInterval(int interval) +{ + timingInterval = interval; + + if (driver->isRunning() && !isPauseTimerActive) { + //we changed the timing interval + driver->stop(); + driver->start(); + } +} + + +void QUnifiedTimer::timerEvent(QTimerEvent *event) +{ + //in the case of consistent timing we make sure the orders in which events come is always the same + //for that purpose we do as if the startstoptimer would always fire before the animation timer + if ((consistentTiming && startStopAnimationTimer.isActive()) || + event->timerId() == startStopAnimationTimer.timerId()) { + startStopAnimationTimer.stop(); + + //we transfer the waiting animations into the "really running" state + animations += animationsToStart; + animationsToStart.clear(); + if (animations.isEmpty()) { + animationTimer.stop(); + isPauseTimerActive = false; + // invalidate the start reference time + time.invalidate(); + } else { + restartAnimationTimer(); + if (!time.isValid()) { + lastTick = 0; + time.start(); + } + } + } + + if (event->timerId() == animationTimer.timerId()) { + // update current time on all top level animations + updateAnimationsTime(); + restartAnimationTimer(); + } +} + +void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation, bool isTopLevel) +{ + QUnifiedTimer *inst = instance(true); //we create the instance if needed + inst->registerRunningAnimation(animation); + if (isTopLevel) { + Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); + QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; + inst->animationsToStart << animation; + if (!inst->startStopAnimationTimer.isActive()) + inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst); + } +} + +void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) +{ + QUnifiedTimer *inst = QUnifiedTimer::instance(false); + if (inst) { + //at this point the unified timer should have been created + //but it might also have been already destroyed in case the application is shutting down + + inst->unregisterRunningAnimation(animation); + + if (!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer) + return; + + int idx = inst->animations.indexOf(animation); + if (idx != -1) { + inst->animations.removeAt(idx); + // this is needed if we unregister an animation while its running + if (idx <= inst->currentAnimationIdx) + --inst->currentAnimationIdx; + + if (inst->animations.isEmpty() && !inst->startStopAnimationTimer.isActive()) + inst->startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, inst); + } else { + inst->animationsToStart.removeOne(animation); + } + } + QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; +} + +void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation) +{ + if (QAbstractAnimationPrivate::get(animation)->isGroup) + return; + + if (QAbstractAnimationPrivate::get(animation)->isPause) { + runningPauseAnimations << animation; + } else + runningLeafAnimations++; +} + +void QUnifiedTimer::unregisterRunningAnimation(QAbstractAnimation *animation) +{ + if (QAbstractAnimationPrivate::get(animation)->isGroup) + return; + + if (QAbstractAnimationPrivate::get(animation)->isPause) + runningPauseAnimations.removeOne(animation); + else + runningLeafAnimations--; + Q_ASSERT(runningLeafAnimations >= 0); +} + +int QUnifiedTimer::closestPauseAnimationTimeToFinish() +{ + int closestTimeToFinish = INT_MAX; + for (int i = 0; i < runningPauseAnimations.size(); ++i) { + QAbstractAnimation *animation = runningPauseAnimations.at(i); + int timeToFinish; + + if (animation->direction() == QAbstractAnimation::Forward) + timeToFinish = animation->duration() - animation->currentLoopTime(); + else + timeToFinish = animation->currentLoopTime(); + + if (timeToFinish < closestTimeToFinish) + closestTimeToFinish = timeToFinish; + } + return closestTimeToFinish; +} + +void QUnifiedTimer::installAnimationDriver(QAnimationDriver *d) +{ + if (driver->isRunning()) { + qWarning("QUnifiedTimer: Cannot change animation driver while animations are running"); + return; + } + + if (driver && driver != &defaultDriver) + delete driver; + + driver = d; +} + +/*! + \class QAnimationDriver + + \brief The QAnimationDriver class is used to exchange the mechanism that drives animations. + + The default animation system is driven by a timer that fires at regular intervals. + In some scenarios, it is better to drive the animation based on other synchronization + mechanisms, such as the vertical refresh rate of the screen. + + \internal + */ + +QAnimationDriver::QAnimationDriver(QObject *parent) + : QObject(*(new QAnimationDriverPrivate), parent) +{ +} + +QAnimationDriver::QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + + +/*! + Advances the animation based on the current time. This function should + be continuously called by the driver while the animation is running. + + \internal + */ +void QAnimationDriver::advance() +{ + QUnifiedTimer *instance = QUnifiedTimer::instance(); + + // update current time on all top level animations + instance->updateAnimationsTime(); + instance->restartAnimationTimer(); +} + + +/*! + Installs this animation driver. The animation driver is thread local and + will only apply for the thread its installed in. + + \internal + */ +void QAnimationDriver::install() +{ + QUnifiedTimer *timer = QUnifiedTimer::instance(true); + timer->installAnimationDriver(this); +} + +bool QAnimationDriver::isRunning() const +{ + return d_func()->running; +} + + +void QAnimationDriver::start() +{ + Q_D(QAnimationDriver); + if (!d->running) { + started(); + d->running = true; + } +} + + +void QAnimationDriver::stop() +{ + Q_D(QAnimationDriver); + if (d->running) { + stopped(); + d->running = false; + } +} + +/*! + \fn QAnimationDriver::started() + + This function is called by the animation framework to notify the driver + that it should start running. + + \internal + */ + +/*! + \fn QAnimationDriver::stopped() + + This function is called by the animation framework to notify the driver + that it should stop running. + + \internal + */ + +/*! + The default animation driver just spins the timer... + */ +QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer) + : QAnimationDriver(0), m_unified_timer(timer) +{ +} + +void QDefaultAnimationDriver::timerEvent(QTimerEvent *e) +{ + Q_ASSERT(e->timerId() == m_timer.timerId()); + Q_UNUSED(e); // if the assertions are disabled + advance(); +} + +void QDefaultAnimationDriver::started() +{ + m_timer.start(m_unified_timer->timingInterval, this); +} + +void QDefaultAnimationDriver::stopped() +{ + m_timer.stop(); +} + + + +void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) +{ + Q_Q(QAbstractAnimation); + if (state == newState) + return; + + if (loopCount == 0) + return; + + QAbstractAnimation::State oldState = state; + int oldCurrentTime = currentTime; + int oldCurrentLoop = currentLoop; + QAbstractAnimation::Direction oldDirection = direction; + + // check if we should Rewind + if ((newState == QAbstractAnimation::Paused || newState == QAbstractAnimation::Running) + && oldState == QAbstractAnimation::Stopped) { + //here we reset the time if needed + //we don't call setCurrentTime because this might change the way the animation + //behaves: changing the state or changing the current value + totalCurrentTime = currentTime = (direction == QAbstractAnimation::Forward) ? + 0 : (loopCount == -1 ? q->duration() : q->totalDuration()); + } + + state = newState; + QWeakPointer guard(q); + + //(un)registration of the animation must always happen before calls to + //virtual function (updateState) to ensure a correct state of the timer + bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; + if (oldState == QAbstractAnimation::Running) { + if (newState == QAbstractAnimation::Paused && hasRegisteredTimer) + QUnifiedTimer::ensureTimerUpdate(); + //the animation, is not running any more + QUnifiedTimer::unregisterAnimation(q); + } else if (newState == QAbstractAnimation::Running) { + QUnifiedTimer::registerAnimation(q, isTopLevel); + } + + q->updateState(newState, oldState); + if (!guard || newState != state) //this is to be safe if updateState changes the state + return; + + // Notify state change + emit q->stateChanged(newState, oldState); + if (!guard || newState != state) //this is to be safe if updateState changes the state + return; + + switch (state) { + case QAbstractAnimation::Paused: + break; + case QAbstractAnimation::Running: + { + + // this ensures that the value is updated now that the animation is running + if (oldState == QAbstractAnimation::Stopped) { + if (isTopLevel) { + // currentTime needs to be updated if pauseTimer is active + QUnifiedTimer::ensureTimerUpdate(); + q->setCurrentTime(totalCurrentTime); + } + } + } + break; + case QAbstractAnimation::Stopped: + // Leave running state. + int dura = q->duration(); + + if (deleteWhenStopped) + q->deleteLater(); + + if (dura == -1 || loopCount < 0 + || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount)) + || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) { + emit q->finished(); + } + break; + } +} + +/*! + Constructs the QAbstractAnimation base class, and passes \a parent to + QObject's constructor. + + \sa QVariantAnimation, QAnimationGroup +*/ +QAbstractAnimation::QAbstractAnimation(QObject *parent) + : QObject(*new QAbstractAnimationPrivate, 0) +{ + // Allow auto-add on reparent + setParent(parent); +} + +/*! + \internal +*/ +QAbstractAnimation::QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent) + : QObject(dd, 0) +{ + // Allow auto-add on reparent + setParent(parent); +} + +/*! + Stops the animation if it's running, then destroys the + QAbstractAnimation. If the animation is part of a QAnimationGroup, it is + automatically removed before it's destroyed. +*/ +QAbstractAnimation::~QAbstractAnimation() +{ + Q_D(QAbstractAnimation); + //we can't call stop here. Otherwise we get pure virtual calls + if (d->state != Stopped) { + QAbstractAnimation::State oldState = d->state; + d->state = Stopped; + emit stateChanged(oldState, d->state); + if (oldState == QAbstractAnimation::Running) + QUnifiedTimer::unregisterAnimation(this); + } +} + +/*! + \property QAbstractAnimation::state + \brief state of the animation. + + This property describes the current state of the animation. When the + animation state changes, QAbstractAnimation emits the stateChanged() + signal. +*/ +QAbstractAnimation::State QAbstractAnimation::state() const +{ + Q_D(const QAbstractAnimation); + return d->state; +} + +/*! + If this animation is part of a QAnimationGroup, this function returns a + pointer to the group; otherwise, it returns 0. + + \sa QAnimationGroup::addAnimation() +*/ +QAnimationGroup *QAbstractAnimation::group() const +{ + Q_D(const QAbstractAnimation); + return d->group; +} + +/*! + \enum QAbstractAnimation::State + + This enum describes the state of the animation. + + \value Stopped The animation is not running. This is the initial state + of QAbstractAnimation, and the state QAbstractAnimation reenters when finished. The current + time remain unchanged until either setCurrentTime() is + called, or the animation is started by calling start(). + + \value Paused The animation is paused (i.e., temporarily + suspended). Calling resume() will resume animation activity. + + \value Running The animation is running. While control is in the event + loop, QAbstractAnimation will update its current time at regular intervals, + calling updateCurrentTime() when appropriate. + + \sa state(), stateChanged() +*/ + +/*! + \enum QAbstractAnimation::Direction + + This enum describes the direction of the animation when in \l Running state. + + \value Forward The current time of the animation increases with time (i.e., + moves from 0 and towards the end / duration). + + \value Backward The current time of the animation decreases with time (i.e., + moves from the end / duration and towards 0). + + \sa direction +*/ + +/*! + \property QAbstractAnimation::direction + \brief the direction of the animation when it is in \l Running + state. + + This direction indicates whether the time moves from 0 towards the + animation duration, or from the value of the duration and towards 0 after + start() has been called. + + By default, this property is set to \l Forward. +*/ +QAbstractAnimation::Direction QAbstractAnimation::direction() const +{ + Q_D(const QAbstractAnimation); + return d->direction; +} +void QAbstractAnimation::setDirection(Direction direction) +{ + Q_D(QAbstractAnimation); + if (d->direction == direction) + return; + + if (state() == Stopped) { + if (direction == Backward) { + d->currentTime = duration(); + d->currentLoop = d->loopCount - 1; + } else { + d->currentTime = 0; + d->currentLoop = 0; + } + } + + // the commands order below is important: first we need to setCurrentTime with the old direction, + // then update the direction on this and all children and finally restart the pauseTimer if needed + if (d->hasRegisteredTimer) + QUnifiedTimer::ensureTimerUpdate(); + + d->direction = direction; + updateDirection(direction); + + if (d->hasRegisteredTimer) + // needed to update the timer interval in case of a pause animation + QUnifiedTimer::updateAnimationTimer(); + + emit directionChanged(direction); +} + +/*! + \property QAbstractAnimation::duration + \brief the duration of the animation. + + If the duration is -1, it means that the duration is undefined. + In this case, loopCount is ignored. +*/ + +/*! + \property QAbstractAnimation::loopCount + \brief the loop count of the animation + + This property describes the loop count of the animation as an integer. + By default this value is 1, indicating that the animation + should run once only, and then stop. By changing it you can let the + animation loop several times. With a value of 0, the animation will not + run at all, and with a value of -1, the animation will loop forever + until stopped. + It is not supported to have loop on an animation that has an undefined + duration. It will only run once. +*/ +int QAbstractAnimation::loopCount() const +{ + Q_D(const QAbstractAnimation); + return d->loopCount; +} +void QAbstractAnimation::setLoopCount(int loopCount) +{ + Q_D(QAbstractAnimation); + d->loopCount = loopCount; +} + +/*! + \property QAbstractAnimation::currentLoop + \brief the current loop of the animation + + This property describes the current loop of the animation. By default, + the animation's loop count is 1, and so the current loop will + always be 0. If the loop count is 2 and the animation runs past its + duration, it will automatically rewind and restart at current time 0, and + current loop 1, and so on. + + When the current loop changes, QAbstractAnimation emits the + currentLoopChanged() signal. +*/ +int QAbstractAnimation::currentLoop() const +{ + Q_D(const QAbstractAnimation); + return d->currentLoop; +} + +/*! + \fn virtual int QAbstractAnimation::duration() const = 0 + + This pure virtual function returns the duration of the animation, and + defines for how long QAbstractAnimation should update the current + time. This duration is local, and does not include the loop count. + + A return value of -1 indicates that the animation has no defined duration; + the animation should run forever until stopped. This is useful for + animations that are not time driven, or where you cannot easily predict + its duration (e.g., event driven audio playback in a game). + + If the animation is a parallel QAnimationGroup, the duration will be the longest + duration of all its animations. If the animation is a sequential QAnimationGroup, + the duration will be the sum of the duration of all its animations. + \sa loopCount +*/ + +/*! + Returns the total and effective duration of the animation, including the + loop count. + + \sa duration(), currentTime +*/ +int QAbstractAnimation::totalDuration() const +{ + int dura = duration(); + if (dura <= 0) + return dura; + int loopcount = loopCount(); + if (loopcount < 0) + return -1; + return dura * loopcount; +} + +/*! + Returns the current time inside the current loop. It can go from 0 to duration(). + + \sa duration(), currentTime +*/ + +int QAbstractAnimation::currentLoopTime() const +{ + Q_D(const QAbstractAnimation); + return d->currentTime; +} + +/*! + \property QAbstractAnimation::currentTime + \brief the current time and progress of the animation + + This property describes the animation's current time. You can change the + current time by calling setCurrentTime, or you can call start() and let + the animation run, setting the current time automatically as the animation + progresses. + + The animation's current time starts at 0, and ends at totalDuration(). + + \sa loopCount, currentLoopTime() + */ +int QAbstractAnimation::currentTime() const +{ + Q_D(const QAbstractAnimation); + return d->totalCurrentTime; +} +void QAbstractAnimation::setCurrentTime(int msecs) +{ + Q_D(QAbstractAnimation); + msecs = qMax(msecs, 0); + + // Calculate new time and loop. + int dura = duration(); + int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount); + if (totalDura != -1) + msecs = qMin(totalDura, msecs); + d->totalCurrentTime = msecs; + + // Update new values. + int oldLoop = d->currentLoop; + d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura)); + if (d->currentLoop == d->loopCount) { + //we're at the end + d->currentTime = qMax(0, dura); + d->currentLoop = qMax(0, d->loopCount - 1); + } else { + if (d->direction == Forward) { + d->currentTime = (dura <= 0) ? msecs : (msecs % dura); + } else { + d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1; + if (d->currentTime == dura) + --d->currentLoop; + } + } + + updateCurrentTime(d->currentTime); + if (d->currentLoop != oldLoop) + emit currentLoopChanged(d->currentLoop); + + // All animations are responsible for stopping the animation when their + // own end state is reached; in this case the animation is time driven, + // and has reached the end. + if ((d->direction == Forward && d->totalCurrentTime == totalDura) + || (d->direction == Backward && d->totalCurrentTime == 0)) { + stop(); + } +} + +/*! + Starts the animation. The \a policy argument says whether or not the + animation should be deleted when it's done. When the animation starts, the + stateChanged() signal is emitted, and state() returns Running. When control + reaches the event loop, the animation will run by itself, periodically + calling updateCurrentTime() as the animation progresses. + + If the animation is currently stopped or has already reached the end, + calling start() will rewind the animation and start again from the beginning. + When the animation reaches the end, the animation will either stop, or + if the loop level is more than 1, it will rewind and continue from the beginning. + + If the animation is already running, this function does nothing. + + \sa stop(), state() +*/ +void QAbstractAnimation::start(DeletionPolicy policy) +{ + Q_D(QAbstractAnimation); + if (d->state == Running) + return; + d->deleteWhenStopped = policy; + d->setState(Running); +} + +/*! + Stops the animation. When the animation is stopped, it emits the stateChanged() + signal, and state() returns Stopped. The current time is not changed. + + If the animation stops by itself after reaching the end (i.e., + currentLoopTime() == duration() and currentLoop() > loopCount() - 1), the + finished() signal is emitted. + + \sa start(), state() + */ +void QAbstractAnimation::stop() +{ + Q_D(QAbstractAnimation); + + if (d->state == Stopped) + return; + + d->setState(Stopped); +} + +/*! + Pauses the animation. When the animation is paused, state() returns Paused. + The value of currentTime will remain unchanged until resume() or start() + is called. If you want to continue from the current time, call resume(). + + \sa start(), state(), resume() + */ +void QAbstractAnimation::pause() +{ + Q_D(QAbstractAnimation); + if (d->state == Stopped) { + qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation"); + return; + } + + d->setState(Paused); +} + +/*! + Resumes the animation after it was paused. When the animation is resumed, + it emits the resumed() and stateChanged() signals. The currenttime is not + changed. + + \sa start(), pause(), state() + */ +void QAbstractAnimation::resume() +{ + Q_D(QAbstractAnimation); + if (d->state != Paused) { + qWarning("QAbstractAnimation::resume: " + "Cannot resume an animation that is not paused"); + return; + } + + d->setState(Running); +} + +/*! + If \a paused is true, the animation is paused. + If \a paused is false, the animation is resumed. + + \sa state(), pause(), resume() +*/ +void QAbstractAnimation::setPaused(bool paused) +{ + if (paused) + pause(); + else + resume(); +} + + +/*! + \reimp +*/ +bool QAbstractAnimation::event(QEvent *event) +{ + return QObject::event(event); +} + +/*! + \fn virtual void QAbstractAnimation::updateCurrentTime(int currentTime) = 0; + + This pure virtual function is called every time the animation's + \a currentTime changes. + + \sa updateState() +*/ + +/*! + This virtual function is called by QAbstractAnimation when the state + of the animation is changed from \a oldState to \a newState. + + \sa start(), stop(), pause(), resume() +*/ +void QAbstractAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_UNUSED(oldState); + Q_UNUSED(newState); +} + +/*! + This virtual function is called by QAbstractAnimation when the direction + of the animation is changed. The \a direction argument is the new direction. + + \sa setDirection(), direction() +*/ +void QAbstractAnimation::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_UNUSED(direction); +} + + +QT_END_NAMESPACE + +#include "moc_qabstractanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h new file mode 100644 index 0000000000..0900870ce2 --- /dev/null +++ b/src/corelib/animation/qabstractanimation.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTANIMATION_H +#define QABSTRACTANIMATION_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QAnimationGroup; +class QSequentialAnimationGroup; +class QAnimationDriver; + +class QAbstractAnimationPrivate; +class Q_CORE_EXPORT QAbstractAnimation : public QObject +{ + Q_OBJECT + Q_ENUMS(State) + Q_ENUMS(Direction) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(int loopCount READ loopCount WRITE setLoopCount) + Q_PROPERTY(int currentTime READ currentTime WRITE setCurrentTime) + Q_PROPERTY(int currentLoop READ currentLoop NOTIFY currentLoopChanged) + Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged) + Q_PROPERTY(int duration READ duration) + +public: + enum Direction { + Forward, + Backward + }; + + enum State { + Stopped, + Paused, + Running + }; + + enum DeletionPolicy { + KeepWhenStopped = 0, + DeleteWhenStopped + }; + + QAbstractAnimation(QObject *parent = 0); + virtual ~QAbstractAnimation(); + + State state() const; + + QAnimationGroup *group() const; + + Direction direction() const; + void setDirection(Direction direction); + + int currentTime() const; + int currentLoopTime() const; + + int loopCount() const; + void setLoopCount(int loopCount); + int currentLoop() const; + + virtual int duration() const = 0; + int totalDuration() const; + +Q_SIGNALS: + void finished(); + void stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + void currentLoopChanged(int currentLoop); + void directionChanged(QAbstractAnimation::Direction); + +public Q_SLOTS: + void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped); + void pause(); + void resume(); + void setPaused(bool); + void stop(); + void setCurrentTime(int msecs); + +protected: + QAbstractAnimation(QAbstractAnimationPrivate &dd, QObject *parent = 0); + bool event(QEvent *event); + + virtual void updateCurrentTime(int currentTime) = 0; + virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + virtual void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QAbstractAnimation) + Q_DECLARE_PRIVATE(QAbstractAnimation) +}; + +class QAnimationDriverPrivate; +class Q_CORE_EXPORT QAnimationDriver : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QAnimationDriver) + +public: + QAnimationDriver(QObject *parent = 0); + + void advance(); + void install(); + + bool isRunning() const; + +protected: + virtual void started() {}; + virtual void stopped() {}; + + QAnimationDriver(QAnimationDriverPrivate &dd, QObject *parent = 0); + +private: + friend class QUnifiedTimer; + + void start(); + void stop(); +}; + + + + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QABSTRACTANIMATION_H diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h new file mode 100644 index 0000000000..ba92960f6b --- /dev/null +++ b/src/corelib/animation/qabstractanimation_p.h @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QABSTRACTANIMATION_P_H +#define QABSTRACTANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_WIN +#include +#endif + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QAnimationGroup; +class QAbstractAnimation; +class QAbstractAnimationPrivate : public QObjectPrivate +{ +public: + QAbstractAnimationPrivate() + : state(QAbstractAnimation::Stopped), + direction(QAbstractAnimation::Forward), + totalCurrentTime(0), + currentTime(0), + loopCount(1), + currentLoop(0), + deleteWhenStopped(false), + hasRegisteredTimer(false), + isPause(false), + isGroup(false), + group(0) + { + } + + virtual ~QAbstractAnimationPrivate() {} + + static QAbstractAnimationPrivate *get(QAbstractAnimation *q) + { + return q->d_func(); + } + + QAbstractAnimation::State state; + QAbstractAnimation::Direction direction; + void setState(QAbstractAnimation::State state); + + int totalCurrentTime; + int currentTime; + int loopCount; + int currentLoop; + + bool deleteWhenStopped; + bool hasRegisteredTimer; + bool isPause; + bool isGroup; + + QAnimationGroup *group; + +private: + Q_DECLARE_PUBLIC(QAbstractAnimation) +}; + + +class QUnifiedTimer; +class QDefaultAnimationDriver : public QAnimationDriver +{ + Q_OBJECT +public: + QDefaultAnimationDriver(QUnifiedTimer *timer); + void timerEvent(QTimerEvent *e); + + void started(); + void stopped(); + +private: + QBasicTimer m_timer; + QUnifiedTimer *m_unified_timer; +}; + +class Q_CORE_EXPORT QAnimationDriverPrivate : public QObjectPrivate +{ +public: + QAnimationDriverPrivate() : running(false) {} + bool running; +}; + +typedef QElapsedTimer ElapsedTimer; + +class Q_CORE_EXPORT QUnifiedTimer : public QObject +{ +private: + QUnifiedTimer(); + +public: + //XXX this is needed by dui + static QUnifiedTimer *instance(); + static QUnifiedTimer *instance(bool create); + + static void registerAnimation(QAbstractAnimation *animation, bool isTopLevel); + static void unregisterAnimation(QAbstractAnimation *animation); + + //defines the timing interval. Default is DEFAULT_TIMER_INTERVAL + void setTimingInterval(int interval); + + /* + this allows to have a consistent timer interval at each tick from the timer + not taking the real time that passed into account. + */ + void setConsistentTiming(bool consistent) { consistentTiming = consistent; } + + //these facilitate fine-tuning of complex animations + void setSlowModeEnabled(bool enabled) { slowMode = enabled; } + void setSlowdownFactor(qreal factor) { slowdownFactor = factor; } + + /* + this is used for updating the currentTime of all animations in case the pause + timer is active or, otherwise, only of the animation passed as parameter. + */ + static void ensureTimerUpdate(); + + /* + this will evaluate the need of restarting the pause timer in case there is still + some pause animations running. + */ + static void updateAnimationTimer(); + + void installAnimationDriver(QAnimationDriver *driver); + + void restartAnimationTimer(); + void updateAnimationsTime(); + +protected: + void timerEvent(QTimerEvent *); + +private: + friend class QDefaultAnimationDriver; + + QAnimationDriver *driver; + QDefaultAnimationDriver defaultDriver; + + QBasicTimer animationTimer; + // timer used to delay the check if we should start/stop the animation timer + QBasicTimer startStopAnimationTimer; + + ElapsedTimer time; + + qint64 lastTick; + int timingInterval; + int currentAnimationIdx; + bool insideTick; + bool consistentTiming; + bool slowMode; + + // This factor will be used to divide the DEFAULT_TIMER_INTERVAL at each tick + // when slowMode is enabled. Setting it to 0 or higher than DEFAULT_TIMER_INTERVAL (16) + // stops all animations. + qreal slowdownFactor; + + // bool to indicate that only pause animations are active + bool isPauseTimerActive; + + QList animations, animationsToStart; + + // this is the count of running animations that are not a group neither a pause animation + int runningLeafAnimations; + QList runningPauseAnimations; + + void registerRunningAnimation(QAbstractAnimation *animation); + void unregisterRunningAnimation(QAbstractAnimation *animation); + + int closestPauseAnimationTimeToFinish(); +}; + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QABSTRACTANIMATION_P_H diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp new file mode 100644 index 0000000000..f3b4f9576e --- /dev/null +++ b/src/corelib/animation/qanimationgroup.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QAnimationGroup + \brief The QAnimationGroup class is an abstract base class for groups of animations. + \since 4.6 + \ingroup animation + + An animation group is a container for animations (subclasses of + QAbstractAnimation). A group is usually responsible for managing + the \l{QAbstractAnimation::State}{state} of its animations, i.e., + it decides when to start, stop, resume, and pause them. Currently, + Qt provides two such groups: QParallelAnimationGroup and + QSequentialAnimationGroup. Look up their class descriptions for + details. + + Since QAnimationGroup inherits from QAbstractAnimation, you can + combine groups, and easily construct complex animation graphs. + You can query QAbstractAnimation for the group it belongs to + (using the \l{QAbstractAnimation::}{group()} function). + + To start a top-level animation group, you simply use the + \l{QAbstractAnimation::}{start()} function from + QAbstractAnimation. By a top-level animation group, we think of a + group that itself is not contained within another group. Starting + sub groups directly is not supported, and may lead to unexpected + behavior. + + \omit OK, we'll put in a snippet on this here \endomit + + QAnimationGroup provides methods for adding and retrieving + animations. Besides that, you can remove animations by calling + remove(), and clear the animation group by calling + clear(). You may keep track of changes in the group's + animations by listening to QEvent::ChildAdded and + QEvent::ChildRemoved events. + + \omit OK, let's find a snippet here as well. \endomit + + QAnimationGroup takes ownership of the animations it manages, and + ensures that they are deleted when the animation group is deleted. + + \sa QAbstractAnimation, QVariantAnimation, {The Animation Framework} +*/ + +#include "qanimationgroup.h" +#include +#include +#include "qanimationgroup_p.h" + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + + +/*! + Constructs a QAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QAnimationGroup::QAnimationGroup(QObject *parent) + : QAbstractAnimation(*new QAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QAnimationGroup::QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent) + : QAbstractAnimation(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QAnimationGroup::~QAnimationGroup() +{ +} + +/*! + Returns a pointer to the animation at \a index in this group. This + function is useful when you need access to a particular animation. \a + index is between 0 and animationCount() - 1. + + \sa animationCount(), indexOfAnimation() +*/ +QAbstractAnimation *QAnimationGroup::animationAt(int index) const +{ + Q_D(const QAnimationGroup); + + if (index < 0 || index >= d->animations.size()) { + qWarning("QAnimationGroup::animationAt: index is out of bounds"); + return 0; + } + + return d->animations.at(index); +} + + +/*! + Returns the number of animations managed by this group. + + \sa indexOfAnimation(), addAnimation(), animationAt() +*/ +int QAnimationGroup::animationCount() const +{ + Q_D(const QAnimationGroup); + return d->animations.size(); +} + +/*! + Returns the index of \a animation. The returned index can be passed + to the other functions that take an index as an argument. + + \sa insertAnimation(), animationAt(), takeAnimation() +*/ +int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const +{ + Q_D(const QAnimationGroup); + return d->animations.indexOf(animation); +} + +/*! + Adds \a animation to this group. This will call insertAnimation with + index equals to animationCount(). + + \note The group takes ownership of the animation. + + \sa removeAnimation() +*/ +void QAnimationGroup::addAnimation(QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + insertAnimation(d->animations.count(), animation); +} + +/*! + Inserts \a animation into this animation group at \a index. + If \a index is 0 the animation is inserted at the beginning. + If \a index is animationCount(), the animation is inserted at the end. + + \note The group takes ownership of the animation. + + \sa takeAnimation(), addAnimation(), indexOfAnimation(), removeAnimation() +*/ +void QAnimationGroup::insertAnimation(int index, QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + + if (index < 0 || index > d->animations.size()) { + qWarning("QAnimationGroup::insertAnimation: index is out of bounds"); + return; + } + + if (QAnimationGroup *oldGroup = animation->group()) + oldGroup->removeAnimation(animation); + + d->animations.insert(index, animation); + QAbstractAnimationPrivate::get(animation)->group = this; + // this will make sure that ChildAdded event is sent to 'this' + animation->setParent(this); + d->animationInsertedAt(index); +} + +/*! + Removes \a animation from this group. The ownership of \a animation is + transferred to the caller. + + \sa takeAnimation(), insertAnimation(), addAnimation() +*/ +void QAnimationGroup::removeAnimation(QAbstractAnimation *animation) +{ + Q_D(QAnimationGroup); + + if (!animation) { + qWarning("QAnimationGroup::remove: cannot remove null animation"); + return; + } + int index = d->animations.indexOf(animation); + if (index == -1) { + qWarning("QAnimationGroup::remove: animation is not part of this group"); + return; + } + + takeAnimation(index); +} + +/*! + Returns the animation at \a index and removes it from the animation group. + + \note The ownership of the animation is transferred to the caller. + + \sa removeAnimation(), addAnimation(), insertAnimation(), indexOfAnimation() +*/ +QAbstractAnimation *QAnimationGroup::takeAnimation(int index) +{ + Q_D(QAnimationGroup); + if (index < 0 || index >= d->animations.size()) { + qWarning("QAnimationGroup::takeAnimation: no animation at index %d", index); + return 0; + } + QAbstractAnimation *animation = d->animations.at(index); + QAbstractAnimationPrivate::get(animation)->group = 0; + // ### removing from list before doing setParent to avoid inifinite recursion + // in ChildRemoved event + d->animations.removeAt(index); + animation->setParent(0); + d->animationRemoved(index, animation); + return animation; +} + +/*! + Removes and deletes all animations in this animation group, and resets the current + time to 0. + + \sa addAnimation(), removeAnimation() +*/ +void QAnimationGroup::clear() +{ + Q_D(QAnimationGroup); + qDeleteAll(d->animations); +} + +/*! + \reimp +*/ +bool QAnimationGroup::event(QEvent *event) +{ + Q_D(QAnimationGroup); + if (event->type() == QEvent::ChildAdded) { + QChildEvent *childEvent = static_cast(event); + if (QAbstractAnimation *a = qobject_cast(childEvent->child())) { + if (a->group() != this) + addAnimation(a); + } + } else if (event->type() == QEvent::ChildRemoved) { + QChildEvent *childEvent = static_cast(event); + QAbstractAnimation *a = static_cast(childEvent->child()); + // You can only rely on the child being a QObject because in the QEvent::ChildRemoved + // case it might be called from the destructor. + int index = d->animations.indexOf(a); + if (index != -1) + takeAnimation(index); + } + return QAbstractAnimation::event(event); +} + + +void QAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *) +{ + Q_Q(QAnimationGroup); + Q_UNUSED(index); + if (animations.isEmpty()) { + currentTime = 0; + q->stop(); + } +} + +QT_END_NAMESPACE + +#include "moc_qanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h new file mode 100644 index 0000000000..b3cc10579e --- /dev/null +++ b/src/corelib/animation/qanimationgroup.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATIONGROUP_H +#define QANIMATIONGROUP_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QAnimationGroupPrivate; +class Q_CORE_EXPORT QAnimationGroup : public QAbstractAnimation +{ + Q_OBJECT + +public: + QAnimationGroup(QObject *parent = 0); + ~QAnimationGroup(); + + QAbstractAnimation *animationAt(int index) const; + int animationCount() const; + int indexOfAnimation(QAbstractAnimation *animation) const; + void addAnimation(QAbstractAnimation *animation); + void insertAnimation(int index, QAbstractAnimation *animation); + void removeAnimation(QAbstractAnimation *animation); + QAbstractAnimation *takeAnimation(int index); + void clear(); + +protected: + QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + +private: + Q_DISABLE_COPY(QAnimationGroup) + Q_DECLARE_PRIVATE(QAnimationGroup) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QANIMATIONGROUP_H diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h new file mode 100644 index 0000000000..278019abb0 --- /dev/null +++ b/src/corelib/animation/qanimationgroup_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATIONGROUP_P_H +#define QANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qanimationgroup.h" + +#include + +#include "private/qabstractanimation_p.h" + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QAnimationGroupPrivate : public QAbstractAnimationPrivate +{ + Q_DECLARE_PUBLIC(QAnimationGroup) +public: + QAnimationGroupPrivate() + { + isGroup = true; + } + + virtual void animationInsertedAt(int) { } + virtual void animationRemoved(int, QAbstractAnimation *); + + void disconnectUncontrolledAnimation(QAbstractAnimation *anim) + { + //0 for the signal here because we might be called from the animation destructor + QObject::disconnect(anim, 0, q_func(), SLOT(_q_uncontrolledAnimationFinished())); + } + + void connectUncontrolledAnimation(QAbstractAnimation *anim) + { + QObject::connect(anim, SIGNAL(finished()), q_func(), SLOT(_q_uncontrolledAnimationFinished())); + } + + QList animations; +}; + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp new file mode 100644 index 0000000000..414cdde23e --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QParallelAnimationGroup + \brief The QParallelAnimationGroup class provides a parallel group of animations. + \since 4.6 + \ingroup animation + + QParallelAnimationGroup--a \l{QAnimationGroup}{container for + animations}--starts all its animations when it is + \l{QAbstractAnimation::start()}{started} itself, i.e., runs all + animations in parallel. The animation group finishes when the + longest lasting animation has finished. + + You can treat QParallelAnimation as any other QAbstractAnimation, + e.g., pause, resume, or add it to other animation groups. + + \code + QParallelAnimationGroup *group = new QParallelAnimationGroup; + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + \endcode + + In this example, \c anim1 and \c anim2 are two + \l{QPropertyAnimation}s that have already been set up. + + \sa QAnimationGroup, QPropertyAnimation, {The Animation Framework} +*/ + + +#include "qparallelanimationgroup.h" +#include "qparallelanimationgroup_p.h" +//#define QANIMATION_DEBUG + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +/*! + Constructs a QParallelAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QParallelAnimationGroup::QParallelAnimationGroup(QObject *parent) + : QAnimationGroup(*new QParallelAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QParallelAnimationGroup::QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, + QObject *parent) + : QAnimationGroup(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QParallelAnimationGroup::~QParallelAnimationGroup() +{ +} + +/*! + \reimp +*/ +int QParallelAnimationGroup::duration() const +{ + Q_D(const QParallelAnimationGroup); + int ret = 0; + + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + const int currentDuration = animation->totalDuration(); + if (currentDuration == -1) + return -1; // Undetermined length + + ret = qMax(ret, currentDuration); + } + + return ret; +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateCurrentTime(int currentTime) +{ + Q_D(QParallelAnimationGroup); + if (d->animations.isEmpty()) + return; + + if (d->currentLoop > d->lastLoop) { + // simulate completion of the loop + int dura = duration(); + if (dura > 0) { + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + if (animation->state() != QAbstractAnimation::Stopped) + d->animations.at(i)->setCurrentTime(dura); // will stop + } + } + } else if (d->currentLoop < d->lastLoop) { + // simulate completion of the loop seeking backwards + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + //we need to make sure the animation is in the right state + //and then rewind it + d->applyGroupState(animation); + animation->setCurrentTime(0); + animation->stop(); + } + } + +#ifdef QANIMATION_DEBUG + qDebug("QParallellAnimationGroup %5d: setCurrentTime(%d), loop:%d, last:%d, timeFwd:%d, lastcurrent:%d, %d", + __LINE__, d->currentTime, d->currentLoop, d->lastLoop, timeFwd, d->lastCurrentTime, state()); +#endif + // finally move into the actual time of the current loop + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + const int dura = animation->totalDuration(); + //if the loopcount is bigger we should always start all animations + if (d->currentLoop > d->lastLoop + //if we're at the end of the animation, we need to start it if it wasn't already started in this loop + //this happens in Backward direction where not all animations are started at the same time + || d->shouldAnimationStart(animation, d->lastCurrentTime > dura /*startIfAtEnd*/)) { + d->applyGroupState(animation); + } + + if (animation->state() == state()) { + animation->setCurrentTime(currentTime); + if (dura > 0 && currentTime > dura) + animation->stop(); + } + } + d->lastLoop = d->currentLoop; + d->lastCurrentTime = currentTime; +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_D(QParallelAnimationGroup); + QAnimationGroup::updateState(newState, oldState); + + switch (newState) { + case Stopped: + for (int i = 0; i < d->animations.size(); ++i) + d->animations.at(i)->stop(); + d->disconnectUncontrolledAnimations(); + break; + case Paused: + for (int i = 0; i < d->animations.size(); ++i) + if (d->animations.at(i)->state() == Running) + d->animations.at(i)->pause(); + break; + case Running: + d->connectUncontrolledAnimations(); + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + if (oldState == Stopped) + animation->stop(); + animation->setDirection(d->direction); + if (d->shouldAnimationStart(animation, oldState == Stopped)) + animation->start(); + } + break; + } +} + +void QParallelAnimationGroupPrivate::_q_uncontrolledAnimationFinished() +{ + Q_Q(QParallelAnimationGroup); + + QAbstractAnimation *animation = qobject_cast(q->sender()); + Q_ASSERT(animation); + + int uncontrolledRunningCount = 0; + if (animation->duration() == -1 || animation->loopCount() < 0) { + QHash::iterator it = uncontrolledFinishTime.begin(); + while (it != uncontrolledFinishTime.end()) { + if (it.key() == animation) { + *it = animation->currentTime(); + } + if (it.value() == -1) + ++uncontrolledRunningCount; + ++it; + } + } + + if (uncontrolledRunningCount > 0) + return; + + int maxDuration = 0; + for (int i = 0; i < animations.size(); ++i) + maxDuration = qMax(maxDuration, animations.at(i)->totalDuration()); + + if (currentTime >= maxDuration) + q->stop(); +} + +void QParallelAnimationGroupPrivate::disconnectUncontrolledAnimations() +{ + QHash::iterator it = uncontrolledFinishTime.begin(); + while (it != uncontrolledFinishTime.end()) { + disconnectUncontrolledAnimation(it.key()); + ++it; + } + + uncontrolledFinishTime.clear(); +} + +void QParallelAnimationGroupPrivate::connectUncontrolledAnimations() +{ + for (int i = 0; i < animations.size(); ++i) { + QAbstractAnimation *animation = animations.at(i); + if (animation->duration() == -1 || animation->loopCount() < 0) { + uncontrolledFinishTime[animation] = -1; + connectUncontrolledAnimation(animation); + } + } +} + +bool QParallelAnimationGroupPrivate::shouldAnimationStart(QAbstractAnimation *animation, bool startIfAtEnd) const +{ + const int dura = animation->totalDuration(); + if (dura == -1) + return !isUncontrolledAnimationFinished(animation); + if (startIfAtEnd) + return currentTime <= dura; + if (direction == QAbstractAnimation::Forward) + return currentTime < dura; + else //direction == QAbstractAnimation::Backward + return currentTime && currentTime <= dura; +} + +void QParallelAnimationGroupPrivate::applyGroupState(QAbstractAnimation *animation) +{ + switch (state) + { + case QAbstractAnimation::Running: + animation->start(); + break; + case QAbstractAnimation::Paused: + animation->pause(); + break; + case QAbstractAnimation::Stopped: + default: + break; + } +} + + +bool QParallelAnimationGroupPrivate::isUncontrolledAnimationFinished(QAbstractAnimation *anim) const +{ + return uncontrolledFinishTime.value(anim, -1) >= 0; +} + +void QParallelAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *anim) +{ + QAnimationGroupPrivate::animationRemoved(index, anim); + disconnectUncontrolledAnimation(anim); + uncontrolledFinishTime.remove(anim); +} + +/*! + \reimp +*/ +void QParallelAnimationGroup::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_D(QParallelAnimationGroup); + //we need to update the direction of the current animation + if (state() != Stopped) { + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + animation->setDirection(direction); + } + } else { + if (direction == Forward) { + d->lastLoop = 0; + d->lastCurrentTime = 0; + } else { + // Looping backwards with loopCount == -1 does not really work well... + d->lastLoop = (d->loopCount == -1 ? 0 : d->loopCount - 1); + d->lastCurrentTime = duration(); + } + } +} + +/*! + \reimp +*/ +bool QParallelAnimationGroup::event(QEvent *event) +{ + return QAnimationGroup::event(event); +} + +QT_END_NAMESPACE + +#include "moc_qparallelanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h new file mode 100644 index 0000000000..5e0fb71799 --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPARALLELANIMATIONGROUP_H +#define QPARALLELANIMATIONGROUP_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QParallelAnimationGroupPrivate; +class Q_CORE_EXPORT QParallelAnimationGroup : public QAnimationGroup +{ + Q_OBJECT + +public: + QParallelAnimationGroup(QObject *parent = 0); + ~QParallelAnimationGroup(); + + int duration() const; + +protected: + QParallelAnimationGroup(QParallelAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + + void updateCurrentTime(int currentTime); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QParallelAnimationGroup) + Q_DECLARE_PRIVATE(QParallelAnimationGroup) + Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished()) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPARALLELANIMATIONGROUP diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h new file mode 100644 index 0000000000..680d41ea21 --- /dev/null +++ b/src/corelib/animation/qparallelanimationgroup_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPARALLELANIMATIONGROUP_P_H +#define QPARALLELANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qparallelanimationgroup.h" +#include "private/qanimationgroup_p.h" +#include + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QParallelAnimationGroupPrivate : public QAnimationGroupPrivate +{ + Q_DECLARE_PUBLIC(QParallelAnimationGroup) +public: + QParallelAnimationGroupPrivate() + : lastLoop(0), lastCurrentTime(0) + { + } + + QHash uncontrolledFinishTime; + int lastLoop; + int lastCurrentTime; + + bool shouldAnimationStart(QAbstractAnimation *animation, bool startIfAtEnd) const; + void applyGroupState(QAbstractAnimation *animation); + bool isUncontrolledAnimationFinished(QAbstractAnimation *anim) const; + void connectUncontrolledAnimations(); + void disconnectUncontrolledAnimations(); + + void animationRemoved(int index, QAbstractAnimation *); + + // private slot + void _q_uncontrolledAnimationFinished(); +}; + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QPARALLELANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp new file mode 100644 index 0000000000..418cb5321d --- /dev/null +++ b/src/corelib/animation/qpauseanimation.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QPauseAnimation + \brief The QPauseAnimation class provides a pause for QSequentialAnimationGroup. + \since 4.6 + \ingroup animation + + If you wish to introduce a delay between animations in a + QSequentialAnimationGroup, you can insert a QPauseAnimation. This + class does not animate anything, but does not + \l{QAbstractAnimation::finished()}{finish} before a specified + number of milliseconds have elapsed from when it was started. You + specify the duration of the pause in the constructor. It can also + be set directly with setDuration(). + + It is not necessary to construct a QPauseAnimation yourself. + QSequentialAnimationGroup provides the convenience functions + \l{QSequentialAnimationGroup::}{addPause()} and + \l{QSequentialAnimationGroup::}{insertPause()}. These functions + simply take the number of milliseconds the pause should last. + + \sa QSequentialAnimationGroup +*/ + +#include "qpauseanimation.h" +#include "qabstractanimation_p.h" + + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QPauseAnimationPrivate : public QAbstractAnimationPrivate +{ +public: + QPauseAnimationPrivate() : QAbstractAnimationPrivate(), duration(250) + { + isPause = true; + } + + int duration; +}; + +/*! + Constructs a QPauseAnimation. + \a parent is passed to QObject's constructor. + The default duration is 0. +*/ + +QPauseAnimation::QPauseAnimation(QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent) +{ +} + +/*! + Constructs a QPauseAnimation. + \a msecs is the duration of the pause. + \a parent is passed to QObject's constructor. +*/ + +QPauseAnimation::QPauseAnimation(int msecs, QObject *parent) : QAbstractAnimation(*new QPauseAnimationPrivate, parent) +{ + setDuration(msecs); +} + +/*! + Destroys the pause animation. +*/ +QPauseAnimation::~QPauseAnimation() +{ +} + +/*! + \property QPauseAnimation::duration + \brief the duration of the pause. + + The duration of the pause. The duration should not be negative. + The default duration is 250 milliseconds. +*/ +int QPauseAnimation::duration() const +{ + Q_D(const QPauseAnimation); + return d->duration; +} + +void QPauseAnimation::setDuration(int msecs) +{ + if (msecs < 0) { + qWarning("QPauseAnimation::setDuration: cannot set a negative duration"); + return; + } + Q_D(QPauseAnimation); + d->duration = msecs; +} + +/*! + \reimp + */ +bool QPauseAnimation::event(QEvent *e) +{ + return QAbstractAnimation::event(e); +} + +/*! + \reimp + */ +void QPauseAnimation::updateCurrentTime(int) +{ +} + + +QT_END_NAMESPACE + +#include "moc_qpauseanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h new file mode 100644 index 0000000000..1da7865256 --- /dev/null +++ b/src/corelib/animation/qpauseanimation.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAUSEANIMATION_P_H +#define QPAUSEANIMATION_P_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPauseAnimationPrivate; + +class Q_CORE_EXPORT QPauseAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(int duration READ duration WRITE setDuration) +public: + QPauseAnimation(QObject *parent = 0); + QPauseAnimation(int msecs, QObject *parent = 0); + ~QPauseAnimation(); + + int duration() const; + void setDuration(int msecs); + +protected: + bool event(QEvent *e); + void updateCurrentTime(int); + +private: + Q_DISABLE_COPY(QPauseAnimation) + Q_DECLARE_PRIVATE(QPauseAnimation) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPAUSEANIMATION_P_H diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp new file mode 100644 index 0000000000..cc642358f0 --- /dev/null +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QPropertyAnimation + \brief The QPropertyAnimation class animates Qt properties + \since 4.6 + + \ingroup animation + + QPropertyAnimation interpolates over \l{Qt's Property System}{Qt + properties}. As property values are stored in \l{QVariant}s, the + class inherits QVariantAnimation, and supports animation of the + same \l{QVariant::Type}{variant types} as its super class. + + A class declaring properties must be a QObject. To make it + possible to animate a property, it must provide a setter (so that + QPropertyAnimation can set the property's value). Note that this + makes it possible to animate many of Qt's widgets. Let's look at + an example: + + \code + QPropertyAnimation *animation = new QPropertyAnimation(myWidget, "geometry"); + animation->setDuration(10000); + animation->setStartValue(QRect(0, 0, 100, 30)); + animation->setEndValue(QRect(250, 250, 100, 30)); + + animation->start(); + \endcode + + The property name and the QObject instance of which property + should be animated are passed to the constructor. You can then + specify the start and end value of the property. The procedure is + equal for properties in classes you have implemented + yourself--just check with QVariantAnimation that your QVariant + type is supported. + + The QVariantAnimation class description explains how to set up the + animation in detail. Note, however, that if a start value is not + set, the property will start at the value it had when the + QPropertyAnimation instance was created. + + QPropertyAnimation works like a charm on its own. For complex + animations that, for instance, contain several objects, + QAnimationGroup is provided. An animation group is an animation + that can contain other animations, and that can manage when its + animations are played. Look at QParallelAnimationGroup for an + example. + + \sa QVariantAnimation, QAnimationGroup, {The Animation Framework} +*/ + +#include "qpropertyanimation.h" +#include "qanimationgroup.h" +#include "qpropertyanimation_p.h" + +#include + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +void QPropertyAnimationPrivate::updateMetaProperty() +{ + if (!target || propertyName.isEmpty()) { + propertyType = QVariant::Invalid; + propertyIndex = -1; + return; + } + + //propertyType will be set to a valid type only if there is a Q_PROPERTY + //otherwise it will be set to QVariant::Invalid at the end of this function + propertyType = targetValue->property(propertyName).userType(); + propertyIndex = targetValue->metaObject()->indexOfProperty(propertyName); + + if (propertyType != QVariant::Invalid) + convertValues(propertyType); + if (propertyIndex == -1) { + //there is no Q_PROPERTY on the object + propertyType = QVariant::Invalid; + if (!targetValue->dynamicPropertyNames().contains(propertyName)) + qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of your QObject", propertyName.constData()); + } else if (!targetValue->metaObject()->property(propertyIndex).isWritable()) { + qWarning("QPropertyAnimation: you're trying to animate the non-writable property %s of your QObject", propertyName.constData()); + } +} + +void QPropertyAnimationPrivate::updateProperty(const QVariant &newValue) +{ + if (state == QAbstractAnimation::Stopped) + return; + + if (!target) { + q_func()->stop(); //the target was destroyed we need to stop the animation + return; + } + + if (newValue.userType() == propertyType) { + //no conversion is needed, we directly call the QMetaObject::metacall + void *data = const_cast(newValue.constData()); + QMetaObject::metacall(targetValue, QMetaObject::WriteProperty, propertyIndex, &data); + } else { + targetValue->setProperty(propertyName.constData(), newValue); + } +} + +/*! + Construct a QPropertyAnimation object. \a parent is passed to QObject's + constructor. +*/ +QPropertyAnimation::QPropertyAnimation(QObject *parent) + : QVariantAnimation(*new QPropertyAnimationPrivate, parent) +{ +} + +/*! + Construct a QPropertyAnimation object. \a parent is passed to QObject's + constructor. The animation changes the property \a propertyName on \a + target. The default duration is 250ms. + + \sa targetObject, propertyName +*/ +QPropertyAnimation::QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent) + : QVariantAnimation(*new QPropertyAnimationPrivate, parent) +{ + setTargetObject(target); + setPropertyName(propertyName); +} + +/*! + Destroys the QPropertyAnimation instance. + */ +QPropertyAnimation::~QPropertyAnimation() +{ + stop(); +} + +/*! + \property QPropertyAnimation::targetObject + \brief the target QObject for this animation. + + This property defines the target QObject for this animation. + */ +QObject *QPropertyAnimation::targetObject() const +{ + return d_func()->target.data(); +} + +void QPropertyAnimation::setTargetObject(QObject *target) +{ + Q_D(QPropertyAnimation); + if (d->targetValue == target) + return; + + if (d->state != QAbstractAnimation::Stopped) { + qWarning("QPropertyAnimation::setTargetObject: you can't change the target of a running animation"); + return; + } + + d->target = d->targetValue = target; + d->updateMetaProperty(); +} + +/*! + \property QPropertyAnimation::propertyName + \brief the target property name for this animation + + This property defines the target property name for this animation. The + property name is required for the animation to operate. + */ +QByteArray QPropertyAnimation::propertyName() const +{ + Q_D(const QPropertyAnimation); + return d->propertyName; +} + +void QPropertyAnimation::setPropertyName(const QByteArray &propertyName) +{ + Q_D(QPropertyAnimation); + if (d->state != QAbstractAnimation::Stopped) { + qWarning("QPropertyAnimation::setPropertyName: you can't change the property name of a running animation"); + return; + } + + d->propertyName = propertyName; + d->updateMetaProperty(); +} + + +/*! + \reimp + */ +bool QPropertyAnimation::event(QEvent *event) +{ + return QVariantAnimation::event(event); +} + +/*! + This virtual function is called by QVariantAnimation whenever the current value + changes. \a value is the new, updated value. It updates the current value + of the property on the target object. + + \sa currentValue, currentTime + */ +void QPropertyAnimation::updateCurrentValue(const QVariant &value) +{ + Q_D(QPropertyAnimation); + d->updateProperty(value); +} + +/*! + \reimp + + If the startValue is not defined when the state of the animation changes from Stopped to Running, + the current property value is used as the initial value for the animation. +*/ +void QPropertyAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_D(QPropertyAnimation); + + if (!d->target && oldState == Stopped) { + qWarning("QPropertyAnimation::updateState (%s): Changing state of an animation without target", + d->propertyName.constData()); + return; + } + + QVariantAnimation::updateState(newState, oldState); + + QPropertyAnimation *animToStop = 0; + { +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(&staticMetaObject)); +#endif + typedef QPair QPropertyAnimationPair; + typedef QHash QPropertyAnimationHash; + static QPropertyAnimationHash hash; + //here we need to use value because we need to know to which pointer + //the animation was referring in case stopped because the target was destroyed + QPropertyAnimationPair key(d->targetValue, d->propertyName); + if (newState == Running) { + d->updateMetaProperty(); + animToStop = hash.value(key, 0); + hash.insert(key, this); + // update the default start value + if (oldState == Stopped) { + d->setDefaultStartEndValue(d->targetValue->property(d->propertyName.constData())); + //let's check if we have a start value and an end value + if (!startValue().isValid() && (d->direction == Backward || !d->defaultStartEndValue.isValid())) { + qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without start value", + d->propertyName.constData(), d->target.data()->metaObject()->className(), + qPrintable(d->target.data()->objectName())); + } + if (!endValue().isValid() && (d->direction == Forward || !d->defaultStartEndValue.isValid())) { + qWarning("QPropertyAnimation::updateState (%s, %s, %s): starting an animation without end value", + d->propertyName.constData(), d->target.data()->metaObject()->className(), + qPrintable(d->target.data()->objectName())); + } + } + } else if (hash.value(key) == this) { + hash.remove(key); + } + } + + //we need to do that after the mutex was unlocked + if (animToStop) { + // try to stop the top level group + QAbstractAnimation *current = animToStop; + while (current->group() && current->state() != Stopped) + current = current->group(); + current->stop(); + } +} + +#include "moc_qpropertyanimation.cpp" + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h new file mode 100644 index 0000000000..379efe10f7 --- /dev/null +++ b/src/corelib/animation/qpropertyanimation.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPROPERTYANIMATION_H +#define QPROPERTYANIMATION_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPropertyAnimationPrivate; +class Q_CORE_EXPORT QPropertyAnimation : public QVariantAnimation +{ + Q_OBJECT + Q_PROPERTY(QByteArray propertyName READ propertyName WRITE setPropertyName) + Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) + +public: + QPropertyAnimation(QObject *parent = 0); + QPropertyAnimation(QObject *target, const QByteArray &propertyName, QObject *parent = 0); + ~QPropertyAnimation(); + + QObject *targetObject() const; + void setTargetObject(QObject *target); + + QByteArray propertyName() const; + void setPropertyName(const QByteArray &propertyName); + +protected: + bool event(QEvent *event); + void updateCurrentValue(const QVariant &value); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + +private: + Q_DISABLE_COPY(QPropertyAnimation) + Q_DECLARE_PRIVATE(QPropertyAnimation) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QPROPERTYANIMATION_H diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h new file mode 100644 index 0000000000..f1df91ed1f --- /dev/null +++ b/src/corelib/animation/qpropertyanimation_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPROPERTYANIMATION_P_H +#define QPROPERTYANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpropertyanimation.h" + +#include "private/qvariantanimation_p.h" + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QPropertyAnimationPrivate : public QVariantAnimationPrivate +{ + Q_DECLARE_PUBLIC(QPropertyAnimation) +public: + QPropertyAnimationPrivate() + : targetValue(0), propertyType(0), propertyIndex(-1) + { + } + + QWeakPointer target; + //we use targetValue to be able to unregister the target from the global hash + QObject *targetValue; + + //for the QProperty + int propertyType; + int propertyIndex; + + QByteArray propertyName; + void updateProperty(const QVariant &); + void updateMetaProperty(); +}; + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QPROPERTYANIMATION_P_H diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp new file mode 100644 index 0000000000..2e73104c6e --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -0,0 +1,588 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QSequentialAnimationGroup + \brief The QSequentialAnimationGroup class provides a sequential group of animations. + \since 4.6 + \ingroup animation + + QSequentialAnimationGroup is a QAnimationGroup that runs its + animations in sequence, i.e., it starts one animation after + another has finished playing. The animations are played in the + order they are added to the group (using + \l{QAnimationGroup::}{addAnimation()} or + \l{QAnimationGroup::}{insertAnimation()}). The animation group + finishes when its last animation has finished. + + At each moment there is at most one animation that is active in + the group; it is returned by currentAnimation(). An empty group + has no current animation. + + A sequential animation group can be treated as any other + animation, i.e., it can be started, stopped, and added to other + groups. You can also call addPause() or insertPause() to add a + pause to a sequential animation group. + + \code + QSequentialAnimationGroup *group = new QSequentialAnimationGroup; + + group->addAnimation(anim1); + group->addAnimation(anim2); + + group->start(); + \endcode + + In this example, \c anim1 and \c anim2 are two already set up + \l{QPropertyAnimation}s. + + \sa QAnimationGroup, QAbstractAnimation, {The Animation Framework} +*/ + +#include "qsequentialanimationgroup.h" +#include "qsequentialanimationgroup_p.h" + +#include "qpauseanimation.h" + +#include + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +bool QSequentialAnimationGroupPrivate::atEnd() const +{ + // we try to detect if we're at the end of the group + //this is true if the following conditions are true: + // 1. we're in the last loop + // 2. the direction is forward + // 3. the current animation is the last one + // 4. the current animation has reached its end + const int animTotalCurrentTime = QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime; + return (currentLoop == loopCount - 1 + && direction == QAbstractAnimation::Forward + && currentAnimation == animations.last() + && animTotalCurrentTime == animationActualTotalDuration(currentAnimationIndex)); +} + +int QSequentialAnimationGroupPrivate::animationActualTotalDuration(int index) const +{ + QAbstractAnimation *anim = animations.at(index); + int ret = anim->totalDuration(); + if (ret == -1 && actualDuration.size() > index) + ret = actualDuration.at(index); //we can try the actual duration there + return ret; +} + +QSequentialAnimationGroupPrivate::AnimationIndex QSequentialAnimationGroupPrivate::indexForCurrentTime() const +{ + Q_ASSERT(!animations.isEmpty()); + + AnimationIndex ret; + int duration = 0; + + for (int i = 0; i < animations.size(); ++i) { + duration = animationActualTotalDuration(i); + + // 'animation' is the current animation if one of these reasons is true: + // 1. it's duration is undefined + // 2. it ends after msecs + // 3. it is the last animation (this can happen in case there is at least 1 uncontrolled animation) + // 4. it ends exactly in msecs and the direction is backwards + if (duration == -1 || currentTime < (ret.timeOffset + duration) + || (currentTime == (ret.timeOffset + duration) && direction == QAbstractAnimation::Backward)) { + ret.index = i; + return ret; + } + + // 'animation' has a non-null defined duration and is not the one at time 'msecs'. + ret.timeOffset += duration; + } + + // this can only happen when one of those conditions is true: + // 1. the duration of the group is undefined and we passed its actual duration + // 2. there are only 0-duration animations in the group + ret.timeOffset -= duration; + ret.index = animations.size() - 1; + return ret; +} + +void QSequentialAnimationGroupPrivate::restart() +{ + // restarting the group by making the first/last animation the current one + if (direction == QAbstractAnimation::Forward) { + lastLoop = 0; + if (currentAnimationIndex == 0) + activateCurrentAnimation(); + else + setCurrentAnimation(0); + } else { // direction == QAbstractAnimation::Backward + lastLoop = loopCount - 1; + int index = animations.size() - 1; + if (currentAnimationIndex == index) + activateCurrentAnimation(); + else + setCurrentAnimation(index); + } +} + +/*! + \internal + This manages advancing the execution of a group running forwards (time has gone forward), + which is the same behaviour for rewinding the execution of a group running backwards + (time has gone backward). +*/ +void QSequentialAnimationGroupPrivate::advanceForwards(const AnimationIndex &newAnimationIndex) +{ + if (lastLoop < currentLoop) { + // we need to fast forward to the end + for (int i = currentAnimationIndex; i < animations.size(); ++i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(animationActualTotalDuration(i)); + } + // this will make sure the current animation is reset to the beginning + if (animations.size() == 1) + // we need to force activation because setCurrentAnimation will have no effect + activateCurrentAnimation(); + else + setCurrentAnimation(0, true); + } + + // and now we need to fast forward from the current position to + for (int i = currentAnimationIndex; i < newAnimationIndex.index; ++i) { //### WRONG, + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(animationActualTotalDuration(i)); + } + // setting the new current animation will happen later +} + +/*! + \internal + This manages rewinding the execution of a group running forwards (time has gone forward), + which is the same behaviour for advancing the execution of a group running backwards + (time has gone backward). +*/ +void QSequentialAnimationGroupPrivate::rewindForwards(const AnimationIndex &newAnimationIndex) +{ + if (lastLoop > currentLoop) { + // we need to fast rewind to the beginning + for (int i = currentAnimationIndex; i >= 0 ; --i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(0); + } + // this will make sure the current animation is reset to the end + if (animations.size() == 1) + // we need to force activation because setCurrentAnimation will have no effect + activateCurrentAnimation(); + else + setCurrentAnimation(animations.count() - 1, true); + } + + // and now we need to fast rewind from the current position to + for (int i = currentAnimationIndex; i > newAnimationIndex.index; --i) { + QAbstractAnimation *anim = animations.at(i); + setCurrentAnimation(i, true); + anim->setCurrentTime(0); + } + // setting the new current animation will happen later +} + +/*! + \fn QSequentialAnimationGroup::currentAnimationChanged(QAbstractAnimation *current) + + QSequentialAnimationGroup emits this signal when currentAnimation + has been changed. \a current is the current animation. + + \sa currentAnimation() +*/ + + +/*! + Constructs a QSequentialAnimationGroup. + \a parent is passed to QObject's constructor. +*/ +QSequentialAnimationGroup::QSequentialAnimationGroup(QObject *parent) + : QAnimationGroup(*new QSequentialAnimationGroupPrivate, parent) +{ +} + +/*! + \internal +*/ +QSequentialAnimationGroup::QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, + QObject *parent) + : QAnimationGroup(dd, parent) +{ +} + +/*! + Destroys the animation group. It will also destroy all its animations. +*/ +QSequentialAnimationGroup::~QSequentialAnimationGroup() +{ +} + +/*! + Adds a pause of \a msecs to this animation group. + The pause is considered as a special type of animation, thus + \l{QAnimationGroup::animationCount()}{animationCount} will be + increased by one. + + \sa insertPause(), QAnimationGroup::addAnimation() +*/ +QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) +{ + QPauseAnimation *pause = new QPauseAnimation(msecs); + addAnimation(pause); + return pause; +} + +/*! + Inserts a pause of \a msecs milliseconds at \a index in this animation + group. + + \sa addPause(), QAnimationGroup::insertAnimation() +*/ +QPauseAnimation *QSequentialAnimationGroup::insertPause(int index, int msecs) +{ + Q_D(const QSequentialAnimationGroup); + + if (index < 0 || index > d->animations.size()) { + qWarning("QSequentialAnimationGroup::insertPause: index is out of bounds"); + return 0; + } + + QPauseAnimation *pause = new QPauseAnimation(msecs); + insertAnimation(index, pause); + return pause; +} + + +/*! + \property QSequentialAnimationGroup::currentAnimation + Returns the animation in the current time. + + \sa currentAnimationChanged() +*/ +QAbstractAnimation *QSequentialAnimationGroup::currentAnimation() const +{ + Q_D(const QSequentialAnimationGroup); + return d->currentAnimation; +} + +/*! + \reimp +*/ +int QSequentialAnimationGroup::duration() const +{ + Q_D(const QSequentialAnimationGroup); + int ret = 0; + + for (int i = 0; i < d->animations.size(); ++i) { + QAbstractAnimation *animation = d->animations.at(i); + const int currentDuration = animation->totalDuration(); + if (currentDuration == -1) + return -1; // Undetermined length + + ret += currentDuration; + } + + return ret; +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateCurrentTime(int currentTime) +{ + Q_D(QSequentialAnimationGroup); + if (!d->currentAnimation) + return; + + const QSequentialAnimationGroupPrivate::AnimationIndex newAnimationIndex = d->indexForCurrentTime(); + + // remove unneeded animations from actualDuration list + while (newAnimationIndex.index < d->actualDuration.size()) + d->actualDuration.removeLast(); + + // newAnimationIndex.index is the new current animation + if (d->lastLoop < d->currentLoop + || (d->lastLoop == d->currentLoop && d->currentAnimationIndex < newAnimationIndex.index)) { + // advancing with forward direction is the same as rewinding with backwards direction + d->advanceForwards(newAnimationIndex); + } else if (d->lastLoop > d->currentLoop + || (d->lastLoop == d->currentLoop && d->currentAnimationIndex > newAnimationIndex.index)) { + // rewinding with forward direction is the same as advancing with backwards direction + d->rewindForwards(newAnimationIndex); + } + + d->setCurrentAnimation(newAnimationIndex.index); + + const int newCurrentTime = currentTime - newAnimationIndex.timeOffset; + + if (d->currentAnimation) { + d->currentAnimation->setCurrentTime(newCurrentTime); + if (d->atEnd()) { + //we make sure that we don't exceed the duration here + d->currentTime += QAbstractAnimationPrivate::get(d->currentAnimation)->totalCurrentTime - newCurrentTime; + stop(); + } + } else { + //the only case where currentAnimation could be null + //is when all animations have been removed + Q_ASSERT(d->animations.isEmpty()); + d->currentTime = 0; + stop(); + } + + d->lastLoop = d->currentLoop; +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_D(QSequentialAnimationGroup); + QAnimationGroup::updateState(newState, oldState); + + if (!d->currentAnimation) + return; + + switch (newState) { + case Stopped: + d->currentAnimation->stop(); + break; + case Paused: + if (oldState == d->currentAnimation->state() + && oldState == QSequentialAnimationGroup::Running) { + d->currentAnimation->pause(); + } + else + d->restart(); + break; + case Running: + if (oldState == d->currentAnimation->state() + && oldState == QSequentialAnimationGroup::Paused) + d->currentAnimation->start(); + else + d->restart(); + break; + } +} + +/*! + \reimp +*/ +void QSequentialAnimationGroup::updateDirection(QAbstractAnimation::Direction direction) +{ + Q_D(QSequentialAnimationGroup); + // we need to update the direction of the current animation + if (state() != Stopped && d->currentAnimation) + d->currentAnimation->setDirection(direction); +} + +/*! + \reimp +*/ +bool QSequentialAnimationGroup::event(QEvent *event) +{ + return QAnimationGroup::event(event); +} + +void QSequentialAnimationGroupPrivate::setCurrentAnimation(int index, bool intermediate) +{ + Q_Q(QSequentialAnimationGroup); + + index = qMin(index, animations.count() - 1); + + if (index == -1) { + Q_ASSERT(animations.isEmpty()); + currentAnimationIndex = -1; + currentAnimation = 0; + return; + } + + // need these two checks below because this func can be called after the current animation + // has been removed + if (index == currentAnimationIndex && animations.at(index) == currentAnimation) + return; + + // stop the old current animation + if (currentAnimation) + currentAnimation->stop(); + + currentAnimation = animations.at(index); + currentAnimationIndex = index; + + emit q->currentAnimationChanged(currentAnimation); + + activateCurrentAnimation(intermediate); +} + +void QSequentialAnimationGroupPrivate::activateCurrentAnimation(bool intermediate) +{ + if (!currentAnimation || state == QSequentialAnimationGroup::Stopped) + return; + + currentAnimation->stop(); + + // we ensure the direction is consistent with the group's direction + currentAnimation->setDirection(direction); + + // connects to the finish signal of uncontrolled animations + if (currentAnimation->totalDuration() == -1) + connectUncontrolledAnimation(currentAnimation); + + currentAnimation->start(); + if (!intermediate && state == QSequentialAnimationGroup::Paused) + currentAnimation->pause(); +} + +void QSequentialAnimationGroupPrivate::_q_uncontrolledAnimationFinished() +{ + Q_Q(QSequentialAnimationGroup); + Q_ASSERT(qobject_cast(q->sender()) == currentAnimation); + + // we trust the duration returned by the animation + while (actualDuration.size() < (currentAnimationIndex + 1)) + actualDuration.append(-1); + actualDuration[currentAnimationIndex] = currentAnimation->currentTime(); + + disconnectUncontrolledAnimation(currentAnimation); + + if ((direction == QAbstractAnimation::Forward && currentAnimation == animations.last()) + || (direction == QAbstractAnimation::Backward && currentAnimationIndex == 0)) { + // we don't handle looping of a group with undefined duration + q->stop(); + } else if (direction == QAbstractAnimation::Forward) { + // set the current animation to be the next one + setCurrentAnimation(currentAnimationIndex + 1); + } else { + // set the current animation to be the previous one + setCurrentAnimation(currentAnimationIndex - 1); + } +} + +/*! + \internal + This method is called whenever an animation is added to + the group at index \a index. + Note: We only support insertion after the current animation +*/ +void QSequentialAnimationGroupPrivate::animationInsertedAt(int index) +{ + if (currentAnimation == 0) + setCurrentAnimation(0); // initialize the current animation + + if (currentAnimationIndex == index + && currentAnimation->currentTime() == 0 && currentAnimation->currentLoop() == 0) { + //in this case we simply insert an animation before the current one has actually started + setCurrentAnimation(index); + } + + //we update currentAnimationIndex in case it has changed (the animation pointer is still valid) + currentAnimationIndex = animations.indexOf(currentAnimation); + + if (index < currentAnimationIndex || currentLoop != 0) { + qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one."); + return; //we're not affected because it is added after the current one + } +} + +/*! + \internal + This method is called whenever an animation is removed from + the group at index \a index. The animation is no more listed when this + method is called. +*/ +void QSequentialAnimationGroupPrivate::animationRemoved(int index, QAbstractAnimation *anim) +{ + Q_Q(QSequentialAnimationGroup); + QAnimationGroupPrivate::animationRemoved(index, anim); + + Q_ASSERT(currentAnimation); // currentAnimation should always be set + + if (actualDuration.size() > index) + actualDuration.removeAt(index); + + const int currentIndex = animations.indexOf(currentAnimation); + if (currentIndex == -1) { + //we're removing the current animation + + disconnectUncontrolledAnimation(currentAnimation); + + if (index < animations.count()) + setCurrentAnimation(index); //let's try to take the next one + else if (index > 0) + setCurrentAnimation(index - 1); + else// case all animations were removed + setCurrentAnimation(-1); + } else if (currentAnimationIndex > index) { + currentAnimationIndex--; + } + + // duration of the previous animations up to the current animation + currentTime = 0; + for (int i = 0; i < currentAnimationIndex; ++i) { + const int current = animationActualTotalDuration(i); + currentTime += current; + } + + if (currentIndex != -1) { + //the current animation is not the one being removed + //so we add its current time to the current time of this group + currentTime += QAbstractAnimationPrivate::get(currentAnimation)->totalCurrentTime; + } + + //let's also update the total current time + totalCurrentTime = currentTime + loopCount * q->duration(); +} + +QT_END_NAMESPACE + +#include "moc_qsequentialanimationgroup.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h new file mode 100644 index 0000000000..3bb766183f --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSEQUENTIALANIMATIONGROUP_H +#define QSEQUENTIALANIMATIONGROUP_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QPauseAnimation; +class QSequentialAnimationGroupPrivate; + +class Q_CORE_EXPORT QSequentialAnimationGroup : public QAnimationGroup +{ + Q_OBJECT + Q_PROPERTY(QAbstractAnimation* currentAnimation READ currentAnimation NOTIFY currentAnimationChanged) + +public: + QSequentialAnimationGroup(QObject *parent = 0); + ~QSequentialAnimationGroup(); + + QPauseAnimation *addPause(int msecs); + QPauseAnimation *insertPause(int index, int msecs); + + QAbstractAnimation *currentAnimation() const; + int duration() const; + +Q_SIGNALS: + void currentAnimationChanged(QAbstractAnimation *current); + +protected: + QSequentialAnimationGroup(QSequentialAnimationGroupPrivate &dd, QObject *parent); + bool event(QEvent *event); + + void updateCurrentTime(int); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + void updateDirection(QAbstractAnimation::Direction direction); + +private: + Q_DISABLE_COPY(QSequentialAnimationGroup) + Q_DECLARE_PRIVATE(QSequentialAnimationGroup) + Q_PRIVATE_SLOT(d_func(), void _q_uncontrolledAnimationFinished()) +}; + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QSEQUENTIALANIMATIONGROUP_H diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h new file mode 100644 index 0000000000..2337e845f3 --- /dev/null +++ b/src/corelib/animation/qsequentialanimationgroup_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSEQUENTIALANIMATIONGROUP_P_H +#define QSEQUENTIALANIMATIONGROUP_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qsequentialanimationgroup.h" +#include "private/qanimationgroup_p.h" + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QSequentialAnimationGroupPrivate : public QAnimationGroupPrivate +{ + Q_DECLARE_PUBLIC(QSequentialAnimationGroup) +public: + QSequentialAnimationGroupPrivate() + : currentAnimation(0), currentAnimationIndex(-1), lastLoop(0) + { } + + + struct AnimationIndex + { + AnimationIndex() : index(0), timeOffset(0) {} + // index points to the animation at timeOffset, skipping 0 duration animations. + // Note that the index semantic is slightly different depending on the direction. + int index; // the index of the animation in timeOffset + int timeOffset; // time offset when the animation at index starts. + }; + + int animationActualTotalDuration(int index) const; + AnimationIndex indexForCurrentTime() const; + + void setCurrentAnimation(int index, bool intermediate = false); + void activateCurrentAnimation(bool intermediate = false); + + void animationInsertedAt(int index); + void animationRemoved(int index, QAbstractAnimation *anim); + + bool atEnd() const; + + QAbstractAnimation *currentAnimation; + int currentAnimationIndex; + + // this is the actual duration of uncontrolled animations + // it helps seeking and even going forward + QList actualDuration; + + void restart(); + int lastLoop; + + // handle time changes + void rewindForwards(const AnimationIndex &newAnimationIndex); + void advanceForwards(const AnimationIndex &newAnimationIndex); + + // private slot + void _q_uncontrolledAnimationFinished(); +}; + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QSEQUENTIALANIMATIONGROUP_P_H diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp new file mode 100644 index 0000000000..c76cb89ff9 --- /dev/null +++ b/src/corelib/animation/qvariantanimation.cpp @@ -0,0 +1,701 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvariantanimation.h" +#include "qvariantanimation_p.h" + +#include +#include +#include +#include + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +/*! + \class QVariantAnimation + \ingroup animation + \brief The QVariantAnimation class provides an abstract base class for animations. + \since 4.6 + + This class is part of \l{The Animation Framework}. It serves as a + base class for property and item animations, with functions for + shared functionality. + + QVariantAnimation cannot be used directly as it is an abstract + class; it has a pure virtual method called updateCurrentValue(). + The class performs interpolation over + \l{QVariant}s, but leaves using the interpolated values to its + subclasses. Currently, Qt provides QPropertyAnimation, which + animates Qt \l{Qt's Property System}{properties}. See the + QPropertyAnimation class description if you wish to animate such + properties. + + You can then set start and end values for the property by calling + setStartValue() and setEndValue(), and finally call start() to + start the animation. QVariantAnimation will interpolate the + property of the target object and emit valueChanged(). To react to + a change in the current value you have to reimplement the + updateCurrentValue() virtual function. + + It is also possible to set values at specified steps situated + between the start and end value. The interpolation will then + touch these points at the specified steps. Note that the start and + end values are defined as the key values at 0.0 and 1.0. + + There are two ways to affect how QVariantAnimation interpolates + the values. You can set an easing curve by calling + setEasingCurve(), and configure the duration by calling + setDuration(). You can change how the QVariants are interpolated + by creating a subclass of QVariantAnimation, and reimplementing + the virtual interpolated() function. + + Subclassing QVariantAnimation can be an alternative if you have + \l{QVariant}s that you do not wish to declare as Qt properties. + Note, however, that you in most cases will be better off declaring + your QVariant as a property. + + Not all QVariant types are supported. Below is a list of currently + supported QVariant types: + + \list + \o \l{QMetaType::}{Int} + \o \l{QMetaType::}{Double} + \o \l{QMetaType::}{Float} + \o \l{QMetaType::}{QLine} + \o \l{QMetaType::}{QLineF} + \o \l{QMetaType::}{QPoint} + \o \l{QMetaType::}{QPointF} + \o \l{QMetaType::}{QSize} + \o \l{QMetaType::}{QSizeF} + \o \l{QMetaType::}{QRect} + \o \l{QMetaType::}{QRectF} + \o \l{QMetaType::}{QColor} + \endlist + + If you need to interpolate other variant types, including custom + types, you have to implement interpolation for these yourself. + To do this, you can register an interpolator function for a given + type. This function takes 3 parameters: the start value, the end value + and the current progress. + + Example: + \code + QVariant myColorInterpolator(const QColor &start, const QColor &end, qreal progress) + { + ... + return QColor(...); + } + ... + qRegisterAnimationInterpolator(myColorInterpolator); + \endcode + + Another option is to reimplement interpolated(), which returns + interpolation values for the value being interpolated. + + \omit We need some snippets around here. \endomit + + \sa QPropertyAnimation, QAbstractAnimation, {The Animation Framework} +*/ + +/*! + \fn void QVariantAnimation::valueChanged(const QVariant &value) + + QVariantAnimation emits this signal whenever the current \a value changes. + + \sa currentValue, startValue, endValue +*/ + +/*! + \fn void QVariantAnimation::updateCurrentValue(const QVariant &value) = 0; + + This pure virtual function is called every time the animation's current + value changes. The \a value argument is the new current value. + + \sa currentValue +*/ + +static bool animationValueLessThan(const QVariantAnimation::KeyValue &p1, const QVariantAnimation::KeyValue &p2) +{ + return p1.first < p2.first; +} + +static QVariant defaultInterpolator(const void *, const void *, qreal) +{ + return QVariant(); +} + +template<> Q_INLINE_TEMPLATE QRect _q_interpolate(const QRect &f, const QRect &t, qreal progress) +{ + QRect ret; + ret.setCoords(_q_interpolate(f.left(), t.left(), progress), + _q_interpolate(f.top(), t.top(), progress), + _q_interpolate(f.right(), t.right(), progress), + _q_interpolate(f.bottom(), t.bottom(), progress)); + return ret; +} + +template<> Q_INLINE_TEMPLATE QRectF _q_interpolate(const QRectF &f, const QRectF &t, qreal progress) +{ + qreal x1, y1, w1, h1; + f.getRect(&x1, &y1, &w1, &h1); + qreal x2, y2, w2, h2; + t.getRect(&x2, &y2, &w2, &h2); + return QRectF(_q_interpolate(x1, x2, progress), _q_interpolate(y1, y2, progress), + _q_interpolate(w1, w2, progress), _q_interpolate(h1, h2, progress)); +} + +template<> Q_INLINE_TEMPLATE QLine _q_interpolate(const QLine &f, const QLine &t, qreal progress) +{ + return QLine( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress)); +} + +template<> Q_INLINE_TEMPLATE QLineF _q_interpolate(const QLineF &f, const QLineF &t, qreal progress) +{ + return QLineF( _q_interpolate(f.p1(), t.p1(), progress), _q_interpolate(f.p2(), t.p2(), progress)); +} + +QVariantAnimationPrivate::QVariantAnimationPrivate() : duration(250), interpolator(&defaultInterpolator) +{ } + +void QVariantAnimationPrivate::convertValues(int t) +{ + //this ensures that all the keyValues are of type t + for (int i = 0; i < keyValues.count(); ++i) { + QVariantAnimation::KeyValue &pair = keyValues[i]; + pair.second.convert(static_cast(t)); + } + //we also need update to the current interval if needed + currentInterval.start.second.convert(static_cast(t)); + currentInterval.end.second.convert(static_cast(t)); + + //... and the interpolator + updateInterpolator(); +} + +void QVariantAnimationPrivate::updateInterpolator() +{ + int type = currentInterval.start.second.userType(); + if (type == currentInterval.end.second.userType()) + interpolator = getInterpolator(type); + else + interpolator = 0; + + //we make sure that the interpolator is always set to something + if (!interpolator) + interpolator = &defaultInterpolator; +} + +/*! + \internal + The goal of this function is to update the currentInterval member. As a consequence, we also + need to update the currentValue. + Set \a force to true to always recalculate the interval. +*/ +void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/) +{ + // can't interpolate if we don't have at least 2 values + if ((keyValues.count() + (defaultStartEndValue.isValid() ? 1 : 0)) < 2) + return; + + const qreal progress = easing.valueForProgress(((duration == 0) ? qreal(1) : qreal(currentTime) / qreal(duration))); + + //0 and 1 are still the boundaries + if (force || (currentInterval.start.first > 0 && progress < currentInterval.start.first) + || (currentInterval.end.first < 1 && progress > currentInterval.end.first)) { + //let's update currentInterval + QVariantAnimation::KeyValues::const_iterator it = qLowerBound(keyValues.constBegin(), + keyValues.constEnd(), + qMakePair(progress, QVariant()), + animationValueLessThan); + if (it == keyValues.constBegin()) { + //the item pointed to by it is the start element in the range + if (it->first == 0 && keyValues.count() > 1) { + currentInterval.start = *it; + currentInterval.end = *(it+1); + } else { + currentInterval.start = qMakePair(qreal(0), defaultStartEndValue); + currentInterval.end = *it; + } + } else if (it == keyValues.constEnd()) { + --it; //position the iterator on the last item + if (it->first == 1 && keyValues.count() > 1) { + //we have an end value (item with progress = 1) + currentInterval.start = *(it-1); + currentInterval.end = *it; + } else { + //we use the default end value here + currentInterval.start = *it; + currentInterval.end = qMakePair(qreal(1), defaultStartEndValue); + } + } else { + currentInterval.start = *(it-1); + currentInterval.end = *it; + } + + // update all the values of the currentInterval + updateInterpolator(); + } + setCurrentValueForProgress(progress); +} + +void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress) +{ + Q_Q(QVariantAnimation); + + const qreal startProgress = currentInterval.start.first; + const qreal endProgress = currentInterval.end.first; + const qreal localProgress = (progress - startProgress) / (endProgress - startProgress); + + QVariant ret = q->interpolated(currentInterval.start.second, + currentInterval.end.second, + localProgress); + qSwap(currentValue, ret); + q->updateCurrentValue(currentValue); + static QBasicAtomicInt changedSignalIndex = Q_BASIC_ATOMIC_INITIALIZER(0); + if (!changedSignalIndex) { + //we keep the mask so that we emit valueChanged only when needed (for performance reasons) + changedSignalIndex.testAndSetRelaxed(0, signalIndex("valueChanged(QVariant)")); + } + if (isSignalConnected(changedSignalIndex) && currentValue != ret) { + //the value has changed + emit q->valueChanged(currentValue); + } +} + +QVariant QVariantAnimationPrivate::valueAt(qreal step) const +{ + QVariantAnimation::KeyValues::const_iterator result = + qBinaryFind(keyValues.begin(), keyValues.end(), qMakePair(step, QVariant()), animationValueLessThan); + if (result != keyValues.constEnd()) + return result->second; + + return QVariant(); +} + +void QVariantAnimationPrivate::setValueAt(qreal step, const QVariant &value) +{ + if (step < qreal(0.0) || step > qreal(1.0)) { + qWarning("QVariantAnimation::setValueAt: invalid step = %f", step); + return; + } + + QVariantAnimation::KeyValue pair(step, value); + + QVariantAnimation::KeyValues::iterator result = qLowerBound(keyValues.begin(), keyValues.end(), pair, animationValueLessThan); + if (result == keyValues.end() || result->first != step) { + keyValues.insert(result, pair); + } else { + if (value.isValid()) + result->second = value; // replaces the previous value + else + keyValues.erase(result); // removes the previous value + } + + recalculateCurrentInterval(/*force=*/true); +} + +void QVariantAnimationPrivate::setDefaultStartEndValue(const QVariant &value) +{ + defaultStartEndValue = value; + recalculateCurrentInterval(/*force=*/true); +} + +/*! + Construct a QVariantAnimation object. \a parent is passed to QAbstractAnimation's + constructor. +*/ +QVariantAnimation::QVariantAnimation(QObject *parent) : QAbstractAnimation(*new QVariantAnimationPrivate, parent) +{ +} + +/*! + \internal +*/ +QVariantAnimation::QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent) : QAbstractAnimation(dd, parent) +{ +} + +/*! + Destroys the animation. +*/ +QVariantAnimation::~QVariantAnimation() +{ +} + +/*! + \property QVariantAnimation::easingCurve + \brief the easing curve of the animation + + This property defines the easing curve of the animation. By + default, a linear easing curve is used, resulting in linear + interpolation. Other curves are provided, for instance, + QEasingCurve::InCirc, which provides a circular entry curve. + Another example is QEasingCurve::InOutElastic, which provides an + elastic effect on the values of the interpolated variant. + + QVariantAnimation will use the QEasingCurve::valueForProgress() to + transform the "normalized progress" (currentTime / totalDuration) + of the animation into the effective progress actually + used by the animation. It is this effective progress that will be + the progress when interpolated() is called. Also, the steps in the + keyValues are referring to this effective progress. + + The easing curve is used with the interpolator, the interpolated() + virtual function, the animation's duration, and iterationCount, to + control how the current value changes as the animation progresses. +*/ +QEasingCurve QVariantAnimation::easingCurve() const +{ + Q_D(const QVariantAnimation); + return d->easing; +} + +void QVariantAnimation::setEasingCurve(const QEasingCurve &easing) +{ + Q_D(QVariantAnimation); + d->easing = easing; + d->recalculateCurrentInterval(); +} + +typedef QVector QInterpolatorVector; +Q_GLOBAL_STATIC(QInterpolatorVector, registeredInterpolators) + +/*! + \fn void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) + \relates QVariantAnimation + \threadsafe + + Registers a custom interpolator \a func for the template type \c{T}. + The interpolator has to be registered before the animation is constructed. + To unregister (and use the default interpolator) set \a func to 0. + */ + +/*! + \internal + \typedef QVariantAnimation::Interpolator + + This is a typedef for a pointer to a function with the following + signature: + \code + QVariant myInterpolator(const QVariant &from, const QVariant &to, qreal progress); + \endcode + +*/ + +/*! \internal + * Registers a custom interpolator \a func for the specific \a interpolationType. + * The interpolator has to be registered before the animation is constructed. + * To unregister (and use the default interpolator) set \a func to 0. + */ +void QVariantAnimation::registerInterpolator(QVariantAnimation::Interpolator func, int interpolationType) +{ + // will override any existing interpolators + QInterpolatorVector *interpolators = registeredInterpolators(); + // When built on solaris with GCC, the destructors can be called + // in such an order that we get here with interpolators == NULL, + // to continue causes the app to crash on exit with a SEGV + if (interpolators) { +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators)); +#endif + if (int(interpolationType) >= interpolators->count()) + interpolators->resize(int(interpolationType) + 1); + interpolators->replace(interpolationType, func); + } +} + + +template static inline QVariantAnimation::Interpolator castToInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) +{ + return reinterpret_cast(func); +} + +QVariantAnimation::Interpolator QVariantAnimationPrivate::getInterpolator(int interpolationType) +{ + QInterpolatorVector *interpolators = registeredInterpolators(); +#ifndef QT_NO_THREAD + QMutexLocker locker(QMutexPool::globalInstanceGet(interpolators)); +#endif + QVariantAnimation::Interpolator ret = 0; + if (interpolationType < interpolators->count()) { + ret = interpolators->at(interpolationType); + if (ret) return ret; + } + + switch(interpolationType) + { + case QMetaType::Int: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::Double: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::Float: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QLine: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QLineF: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QPoint: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QPointF: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QSize: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QSizeF: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QRect: + return castToInterpolator(_q_interpolateVariant); + case QMetaType::QRectF: + return castToInterpolator(_q_interpolateVariant); + default: + return 0; //this type is not handled + } +} + +/*! + \property QVariantAnimation::duration + \brief the duration of the animation + + This property describes the duration in milliseconds of the + animation. The default duration is 250 milliseconds. + + \sa QAbstractAnimation::duration() + */ +int QVariantAnimation::duration() const +{ + Q_D(const QVariantAnimation); + return d->duration; +} + +void QVariantAnimation::setDuration(int msecs) +{ + Q_D(QVariantAnimation); + if (msecs < 0) { + qWarning("QVariantAnimation::setDuration: cannot set a negative duration"); + return; + } + if (d->duration == msecs) + return; + d->duration = msecs; + d->recalculateCurrentInterval(); +} + +/*! + \property QVariantAnimation::startValue + \brief the optional start value of the animation + + This property describes the optional start value of the animation. If + omitted, or if a null QVariant is assigned as the start value, the + animation will use the current position of the end when the animation + is started. + + \sa endValue +*/ +QVariant QVariantAnimation::startValue() const +{ + return keyValueAt(0); +} + +void QVariantAnimation::setStartValue(const QVariant &value) +{ + setKeyValueAt(0, value); +} + +/*! + \property QVariantAnimation::endValue + \brief the end value of the animation + + This property describes the end value of the animation. + + \sa startValue + */ +QVariant QVariantAnimation::endValue() const +{ + return keyValueAt(1); +} + +void QVariantAnimation::setEndValue(const QVariant &value) +{ + setKeyValueAt(1, value); +} + + +/*! + Returns the key frame value for the given \a step. The given \a step + must be in the range 0 to 1. If there is no KeyValue for \a step, + it returns an invalid QVariant. + + \sa keyValues(), setKeyValueAt() +*/ +QVariant QVariantAnimation::keyValueAt(qreal step) const +{ + return d_func()->valueAt(step); +} + +/*! + \typedef QVariantAnimation::KeyValue + + This is a typedef for QPair. +*/ +/*! + \typedef QVariantAnimation::KeyValues + + This is a typedef for QVector +*/ + +/*! + Creates a key frame at the given \a step with the given \a value. + The given \a step must be in the range 0 to 1. + + \sa setKeyValues(), keyValueAt() +*/ +void QVariantAnimation::setKeyValueAt(qreal step, const QVariant &value) +{ + d_func()->setValueAt(step, value); +} + +/*! + Returns the key frames of this animation. + + \sa keyValueAt(), setKeyValues() +*/ +QVariantAnimation::KeyValues QVariantAnimation::keyValues() const +{ + return d_func()->keyValues; +} + +/*! + Replaces the current set of key frames with the given \a keyValues. + the step of the key frames must be in the range 0 to 1. + + \sa keyValues(), keyValueAt() +*/ +void QVariantAnimation::setKeyValues(const KeyValues &keyValues) +{ + Q_D(QVariantAnimation); + d->keyValues = keyValues; + qSort(d->keyValues.begin(), d->keyValues.end(), animationValueLessThan); + d->recalculateCurrentInterval(/*force=*/true); +} + +/*! + \property QVariantAnimation::currentValue + \brief the current value of the animation. + + This property describes the current value; an interpolated value + between the \l{startValue}{start value} and the \l{endValue}{end + value}, using the current time for progress. The value itself is + obtained from interpolated(), which is called repeatedly as the + animation is running. + + QVariantAnimation calls the virtual updateCurrentValue() function + when the current value changes. This is particularly useful for + subclasses that need to track updates. For example, + QPropertyAnimation uses this function to animate Qt \l{Qt's + Property System}{properties}. + + \sa startValue, endValue +*/ +QVariant QVariantAnimation::currentValue() const +{ + Q_D(const QVariantAnimation); + if (!d->currentValue.isValid()) + const_cast(d)->recalculateCurrentInterval(); + return d->currentValue; +} + +/*! + \reimp + */ +bool QVariantAnimation::event(QEvent *event) +{ + return QAbstractAnimation::event(event); +} + +/*! + \reimp +*/ +void QVariantAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) +{ + Q_UNUSED(oldState); + Q_UNUSED(newState); +} + +/*! + + This virtual function returns the linear interpolation between + variants \a from and \a to, at \a progress, usually a value + between 0 and 1. You can reimplement this function in a subclass + of QVariantAnimation to provide your own interpolation algorithm. + + Note that in order for the interpolation to work with a + QEasingCurve that return a value smaller than 0 or larger than 1 + (such as QEasingCurve::InBack) you should make sure that it can + extrapolate. If the semantic of the datatype does not allow + extrapolation this function should handle that gracefully. + + You should call the QVariantAnimation implementation of this + function if you want your class to handle the types already + supported by Qt (see class QVariantAnimation description for a + list of supported types). + + \sa QEasingCurve + */ +QVariant QVariantAnimation::interpolated(const QVariant &from, const QVariant &to, qreal progress) const +{ + return d_func()->interpolator(from.constData(), to.constData(), progress); +} + +/*! + \reimp + */ +void QVariantAnimation::updateCurrentTime(int) +{ + d_func()->recalculateCurrentInterval(); +} + +QT_END_NAMESPACE + +#include "moc_qvariantanimation.cpp" + +#endif //QT_NO_ANIMATION diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h new file mode 100644 index 0000000000..d6badf513a --- /dev/null +++ b/src/corelib/animation/qvariantanimation.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATION_H +#define QANIMATION_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_ANIMATION + +class QVariantAnimationPrivate; +class Q_CORE_EXPORT QVariantAnimation : public QAbstractAnimation +{ + Q_OBJECT + Q_PROPERTY(QVariant startValue READ startValue WRITE setStartValue) + Q_PROPERTY(QVariant endValue READ endValue WRITE setEndValue) + Q_PROPERTY(QVariant currentValue READ currentValue NOTIFY valueChanged) + Q_PROPERTY(int duration READ duration WRITE setDuration) + Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve) + +public: + typedef QPair KeyValue; + typedef QVector KeyValues; + + QVariantAnimation(QObject *parent = 0); + ~QVariantAnimation(); + + QVariant startValue() const; + void setStartValue(const QVariant &value); + + QVariant endValue() const; + void setEndValue(const QVariant &value); + + QVariant keyValueAt(qreal step) const; + void setKeyValueAt(qreal step, const QVariant &value); + + KeyValues keyValues() const; + void setKeyValues(const KeyValues &values); + + QVariant currentValue() const; + + int duration() const; + void setDuration(int msecs); + + QEasingCurve easingCurve() const; + void setEasingCurve(const QEasingCurve &easing); + + typedef QVariant (*Interpolator)(const void *from, const void *to, qreal progress); + +Q_SIGNALS: + void valueChanged(const QVariant &value); + +protected: + QVariantAnimation(QVariantAnimationPrivate &dd, QObject *parent = 0); + bool event(QEvent *event); + + void updateCurrentTime(int); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); + + virtual void updateCurrentValue(const QVariant &value) = 0; + virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const; + +private: + template friend void qRegisterAnimationInterpolator(QVariant (*func)(const T &, const T &, qreal)); + static void registerInterpolator(Interpolator func, int interpolationType); + + Q_DISABLE_COPY(QVariantAnimation) + Q_DECLARE_PRIVATE(QVariantAnimation) +}; + +template +void qRegisterAnimationInterpolator(QVariant (*func)(const T &from, const T &to, qreal progress)) { + QVariantAnimation::registerInterpolator(reinterpret_cast(func), qMetaTypeId()); +} + +#endif //QT_NO_ANIMATION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QANIMATION_H diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h new file mode 100644 index 0000000000..2a8d9d4f07 --- /dev/null +++ b/src/corelib/animation/qvariantanimation_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QANIMATION_P_H +#define QANIMATION_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of QIODevice. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qvariantanimation.h" +#include +#include +#include + +#include "private/qabstractanimation_p.h" + +#ifndef QT_NO_ANIMATION + +QT_BEGIN_NAMESPACE + +class QVariantAnimationPrivate : public QAbstractAnimationPrivate +{ + Q_DECLARE_PUBLIC(QVariantAnimation) +public: + + QVariantAnimationPrivate(); + + static QVariantAnimationPrivate *get(QVariantAnimation *q) + { + return q->d_func(); + } + + void setDefaultStartEndValue(const QVariant &value); + + + QVariant currentValue; + QVariant defaultStartEndValue; + + //this is used to keep track of the KeyValue interval in which we currently are + struct + { + QVariantAnimation::KeyValue start, end; + } currentInterval; + + QEasingCurve easing; + int duration; + QVariantAnimation::KeyValues keyValues; + QVariantAnimation::Interpolator interpolator; + + void setCurrentValueForProgress(const qreal progress); + void recalculateCurrentInterval(bool force=false); + void setValueAt(qreal, const QVariant &); + QVariant valueAt(qreal step) const; + void convertValues(int t); + + void updateInterpolator(); + + //XXX this is needed by dui + static Q_CORE_EXPORT QVariantAnimation::Interpolator getInterpolator(int interpolationType); +}; + +//this should make the interpolation faster +template inline T _q_interpolate(const T &f, const T &t, qreal progress) +{ + return T(f + (t - f) * progress); +} + +template inline QVariant _q_interpolateVariant(const T &from, const T &to, qreal progress) +{ + return _q_interpolate(from, to, progress); +} + + +QT_END_NAMESPACE + +#endif //QT_NO_ANIMATION + +#endif //QANIMATION_P_H diff --git a/src/corelib/arch/alpha/arch.pri b/src/corelib/arch/alpha/arch.pri new file mode 100644 index 0000000000..448a531f07 --- /dev/null +++ b/src/corelib/arch/alpha/arch.pri @@ -0,0 +1,4 @@ +# +# Alpha architecture +# +!*-g++*:SOURCES += $$QT_ARCH_CPP/qatomic_alpha.s diff --git a/src/corelib/arch/alpha/qatomic_alpha.s b/src/corelib/arch/alpha/qatomic_alpha.s new file mode 100644 index 0000000000..d225de794b --- /dev/null +++ b/src/corelib/arch/alpha/qatomic_alpha.s @@ -0,0 +1,239 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .set noreorder + .set volatile + .set noat + .arch ev4 + .text + .align 2 + .align 4 + .globl q_atomic_test_and_set_int + .ent q_atomic_test_and_set_int +q_atomic_test_and_set_int: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + cmpeq $0,$17,$0 + beq $0,3f + mov $18,$0 + stl_c $0,0($16) + beq $0,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_test_and_set_int + .align 2 + .align 4 + .globl q_atomic_test_and_set_acquire_int + .ent q_atomic_test_and_set_acquire_int +q_atomic_test_and_set_acquire_int: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + cmpeq $0,$17,$0 + beq $0,3f + mov $18,$0 + stl_c $0,0($16) + beq $0,2f + br 3f +2: br 1b +3: mb + addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_test_and_set_acquire_int + .align 2 + .align 4 + .globl q_atomic_test_and_set_release_int + .ent q_atomic_test_and_set_release_int +q_atomic_test_and_set_release_int: + .frame $30,0,$26,0 + .prologue 0 + mb +1: ldl_l $0,0($16) + cmpeq $0,$17,$0 + beq $0,3f + mov $18,$0 + stl_c $0,0($16) + beq $0,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_test_and_set_release_int + .align 2 + .align 4 + .globl q_atomic_test_and_set_ptr + .ent q_atomic_test_and_set_ptr +q_atomic_test_and_set_ptr: + .frame $30,0,$26,0 + .prologue 0 +1: ldq_l $0,0($16) + cmpeq $0,$17,$0 + beq $0,3f + mov $18,$0 + stq_c $0,0($16) + beq $0,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_test_and_set_ptr + .align 2 + .align 4 + .globl q_atomic_increment + .ent q_atomic_increment +q_atomic_increment: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + addl $0,1,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + cmpeq $0,$1,$0 + xor $0,1,$0 + ret $31,($26),1 + .end q_atomic_increment + .align 2 + .align 4 + .globl q_atomic_decrement + .ent q_atomic_decrement +q_atomic_decrement: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + subl $0,1,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + cmpeq $0,1,$0 + xor $0,1,$0 + ret $31,($26),1 + .end q_atomic_decrement + .align 2 + .align 4 + .globl q_atomic_set_int + .ent q_atomic_set_int +q_atomic_set_int: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + mov $17,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_set_int + .align 2 + .align 4 + .globl q_atomic_set_ptr + .ent q_atomic_set_ptr +q_atomic_set_ptr: + .frame $30,0,$26,0 + .prologue 0 +1: ldq_l $0,0($16) + mov $17,$1 + stq_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: ret $31,($26),1 + .end q_atomic_set_ptr + + .align 2 + .align 4 + .globl q_atomic_fetch_and_add_int + .ent q_atomic_fetch_and_add_int +q_atomic_fetch_and_add_int: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + addl $0,$17,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_fetch_and_add_int + + .align 2 + .align 4 + .globl q_atomic_fetch_and_add_acquire_int + .ent q_atomic_fetch_and_add_acquire_int +q_atomic_fetch_and_add_acquire_int: + .frame $30,0,$26,0 + .prologue 0 +1: ldl_l $0,0($16) + addl $0,$17,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: mb + addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_fetch_and_add_acquire_int + + .align 2 + .align 4 + .globl q_atomic_fetch_and_add_release_int + .ent q_atomic_fetch_and_add_release_int +q_atomic_fetch_and_add_release_int: + .frame $30,0,$26,0 + .prologue 0 + mb +1: ldl_l $0,0($16) + addl $0,$17,$1 + stl_c $1,0($16) + beq $1,2f + br 3f +2: br 1b +3: addl $31,$0,$0 + ret $31,($26),1 + .end q_atomic_fetch_and_add_release_int diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri new file mode 100644 index 0000000000..cd23e5e855 --- /dev/null +++ b/src/corelib/arch/arch.pri @@ -0,0 +1,38 @@ +win32:HEADERS += arch/qatomic_windows.h \ + arch/qatomic_generic.h + +win32-g++*:HEADERS += arch/qatomic_i386.h \ + arch/qatomic_x86_64.h + +mac:HEADERS += arch/qatomic_macosx.h \ + arch/qatomic_generic.h + +symbian:HEADERS += arch/qatomic_symbian.h \ + arch/qatomic_generic.h + +vxworks:HEADERS += arch/qatomic_vxworks.h + +integrity:HEADERS += arch/qatomic_integrity.h + +!wince*:!win32:!mac:!symbian:HEADERS += arch/qatomic_alpha.h \ + arch/qatomic_avr32.h \ + arch/qatomic_ia64.h \ + arch/qatomic_parisc.h \ + arch/qatomic_sparc.h \ + arch/qatomic_arch.h \ + arch/qatomic_generic.h \ + arch/qatomic_powerpc.h \ + arch/qatomic_arm.h \ + arch/qatomic_armv5.h \ + arch/qatomic_armv6.h \ + arch/qatomic_armv7.h \ + arch/qatomic_i386.h \ + arch/qatomic_mips.h \ + arch/qatomic_s390.h \ + arch/qatomic_x86_64.h \ + arch/qatomic_sh.h \ + arch/qatomic_sh4a.h + +QT_ARCH_CPP = $$QT_SOURCE_TREE/src/corelib/arch/$$QT_ARCH +DEPENDPATH += $$QT_ARCH_CPP +include($$QT_ARCH_CPP/arch.pri, "", true) diff --git a/src/corelib/arch/arm/arch.pri b/src/corelib/arch/arm/arch.pri new file mode 100644 index 0000000000..79e4bfc115 --- /dev/null +++ b/src/corelib/arch/arm/arch.pri @@ -0,0 +1,4 @@ +# +# ARM architecture +# +SOURCES += $$QT_ARCH_CPP/qatomic_arm.cpp diff --git a/src/corelib/arch/arm/qatomic_arm.cpp b/src/corelib/arch/arm/qatomic_arm.cpp new file mode 100644 index 0000000000..8f06515247 --- /dev/null +++ b/src/corelib/arch/arm/qatomic_arm.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#ifdef _POSIX_PRIORITY_SCHEDULING +# include +#endif +#include + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +Q_CORE_EXPORT char q_atomic_lock = 0; + +Q_CORE_EXPORT void qt_atomic_yield(int *count) +{ +#ifdef _POSIX_PRIORITY_SCHEDULING + if((*count)++ < 50) { + sched_yield(); + } else +#endif + { + struct timespec tm; + tm.tv_sec = 0; + tm.tv_nsec = 2000001; + nanosleep(&tm, NULL); + *count = 0; + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/arch/avr32/arch.pri b/src/corelib/arch/avr32/arch.pri new file mode 100644 index 0000000000..37f231ee61 --- /dev/null +++ b/src/corelib/arch/avr32/arch.pri @@ -0,0 +1,3 @@ +# +# AVR32 architecture +# diff --git a/src/corelib/arch/bfin/arch.pri b/src/corelib/arch/bfin/arch.pri new file mode 100644 index 0000000000..fa198ae8bb --- /dev/null +++ b/src/corelib/arch/bfin/arch.pri @@ -0,0 +1,3 @@ +# +# Blackfin architecture +# diff --git a/src/corelib/arch/generic/arch.pri b/src/corelib/arch/generic/arch.pri new file mode 100644 index 0000000000..8fee63fa5d --- /dev/null +++ b/src/corelib/arch/generic/arch.pri @@ -0,0 +1,6 @@ +# +# 'generic' architecture +# + +unix:SOURCES += qatomic_generic_unix.cpp +win32:SOURCES += qatomic_generic_windows.cpp diff --git a/src/corelib/arch/generic/qatomic_generic_unix.cpp b/src/corelib/arch/generic/qatomic_generic_unix.cpp new file mode 100644 index 0000000000..5ab4c6b943 --- /dev/null +++ b/src/corelib/arch/generic/qatomic_generic_unix.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#if !defined(Q_OS_SYMBIAN) || (defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT)) + +#include "qplatformdefs.h" + +#include + +QT_BEGIN_NAMESPACE +static pthread_mutex_t qAtomicMutex = PTHREAD_MUTEX_INITIALIZER; + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + bool returnValue = false; + pthread_mutex_lock(&qAtomicMutex); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ + int returnValue; + pthread_mutex_lock(&qAtomicMutex); + returnValue = *_q_value; + *_q_value = newValue; + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + int returnValue; + pthread_mutex_lock(&qAtomicMutex); + returnValue = *_q_value; + *_q_value += valueToAdd; + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + bool returnValue = false; + pthread_mutex_lock(&qAtomicMutex); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + void *returnValue; + pthread_mutex_lock(&qAtomicMutex); + returnValue = *_q_value; + *_q_value = newValue; + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + void *returnValue; + pthread_mutex_lock(&qAtomicMutex); + returnValue = *_q_value; + *_q_value = reinterpret_cast(returnValue) + valueToAdd; + pthread_mutex_unlock(&qAtomicMutex); + return returnValue; +} +QT_END_NAMESPACE +#endif //!defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT) diff --git a/src/corelib/arch/generic/qatomic_generic_windows.cpp b/src/corelib/arch/generic/qatomic_generic_windows.cpp new file mode 100644 index 0000000000..c2496db45c --- /dev/null +++ b/src/corelib/arch/generic/qatomic_generic_windows.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include + + +class QCriticalSection +{ +public: + QCriticalSection() { InitializeCriticalSection(§ion); } + ~QCriticalSection() { DeleteCriticalSection(§ion); } + void lock() { EnterCriticalSection(§ion); } + void unlock() { LeaveCriticalSection(§ion); } + +private: + CRITICAL_SECTION section; +}; + +static QCriticalSection qAtomicCriticalSection; + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + bool returnValue = false; + qAtomicCriticalSection.lock(); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ + int returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = newValue; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + int returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value += valueToAdd; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + bool returnValue = false; + qAtomicCriticalSection.lock(); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + void *returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = newValue; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + void *returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = reinterpret_cast(returnValue) + valueToAdd; + qAtomicCriticalSection.unlock(); + return returnValue; +} diff --git a/src/corelib/arch/i386/arch.pri b/src/corelib/arch/i386/arch.pri new file mode 100644 index 0000000000..3101dae01b --- /dev/null +++ b/src/corelib/arch/i386/arch.pri @@ -0,0 +1,4 @@ +# +# i386 architecture +# +!*-g++*:!*-icc*:SOURCES += $$QT_ARCH_CPP/qatomic_i386.s diff --git a/src/corelib/arch/i386/qatomic_i386.s b/src/corelib/arch/i386/qatomic_i386.s new file mode 100644 index 0000000000..08158f926b --- /dev/null +++ b/src/corelib/arch/i386/qatomic_i386.s @@ -0,0 +1,103 @@ + .text + + .align 4,0x90 + .globl q_atomic_test_and_set_int +q_atomic_test_and_set_int: + movl 4(%esp),%ecx + movl 8(%esp),%eax + movl 12(%esp),%edx + lock + cmpxchgl %edx,(%ecx) + mov $0,%eax + sete %al + ret + .align 4,0x90 + .type q_atomic_test_and_set_int,@function + .size q_atomic_test_and_set_int,.-q_atomic_test_and_set_int + + .align 4,0x90 + .globl q_atomic_test_and_set_ptr +q_atomic_test_and_set_ptr: + movl 4(%esp),%ecx + movl 8(%esp),%eax + movl 12(%esp),%edx + lock + cmpxchgl %edx,(%ecx) + mov $0,%eax + sete %al + ret + .align 4,0x90 + .type q_atomic_test_and_set_ptr,@function + .size q_atomic_test_and_set_ptr,.-q_atomic_test_and_set_ptr + + .align 4,0x90 + .globl q_atomic_increment +q_atomic_increment: + movl 4(%esp), %ecx + lock + incl (%ecx) + mov $0,%eax + setne %al + ret + .align 4,0x90 + .type q_atomic_increment,@function + .size q_atomic_increment,.-q_atomic_increment + + .align 4,0x90 + .globl q_atomic_decrement +q_atomic_decrement: + movl 4(%esp), %ecx + lock + decl (%ecx) + mov $0,%eax + setne %al + ret + .align 4,0x90 + .type q_atomic_decrement,@function + .size q_atomic_decrement,.-q_atomic_decrement + + .align 4,0x90 + .globl q_atomic_set_int +q_atomic_set_int: + mov 4(%esp),%ecx + mov 8(%esp),%eax + xchgl %eax,(%ecx) + ret + .align 4,0x90 + .type q_atomic_set_int,@function + .size q_atomic_set_int,.-q_atomic_set_int + + .align 4,0x90 + .globl q_atomic_set_ptr +q_atomic_set_ptr: + mov 4(%esp),%ecx + mov 8(%esp),%eax + xchgl %eax,(%ecx) + ret + .align 4,0x90 + .type q_atomic_set_ptr,@function + .size q_atomic_set_ptr,.-q_atomic_set_ptr + + .align 4,0x90 + .globl q_atomic_fetch_and_add_int +q_atomic_fetch_and_add_int: + mov 4(%esp),%ecx + mov 8(%esp),%eax + lock + xadd %eax,(%ecx) + ret + .align 4,0x90 + .type q_atomic_fetch_and_add_int,@function + .size q_atomic_fetch_and_add_int,.-q_atomic_fetch_and_add_int + + .align 4,0x90 + .globl q_atomic_fetch_and_add_ptr +q_atomic_fetch_and_add_ptr: + mov 4(%esp),%ecx + mov 8(%esp),%eax + lock + xadd %eax,(%ecx) + ret + .align 4,0x90 + .type q_atomic_fetch_and_add_ptr,@function + .size q_atomic_fetch_and_add_ptr,.-q_atomic_fetch_and_add_ptr diff --git a/src/corelib/arch/ia64/arch.pri b/src/corelib/arch/ia64/arch.pri new file mode 100644 index 0000000000..63afa967a4 --- /dev/null +++ b/src/corelib/arch/ia64/arch.pri @@ -0,0 +1,4 @@ +# +# Intel Itanium architecture +# +!*-g++:!*-icc:!hpuxi-acc-*:SOURCES += $$QT_ARCH_CPP/qatomic_ia64.s diff --git a/src/corelib/arch/ia64/qatomic_ia64.s b/src/corelib/arch/ia64/qatomic_ia64.s new file mode 100644 index 0000000000..c988cfcd10 --- /dev/null +++ b/src/corelib/arch/ia64/qatomic_ia64.s @@ -0,0 +1,74 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .pred.safe_across_calls p1-p5,p16-p63 +.text + .align 16 + .global q_atomic_test_and_set_int# + .proc q_atomic_test_and_set_int# +q_atomic_test_and_set_int: + .prologue + .body + mov ar.ccv=r33 + ;; + cmpxchg4.acq r34=[r32],r34,ar.ccv + ;; + cmp4.eq p6, p7 = r33, r34 + ;; + (p6) addl r8 = 1, r0 + (p7) mov r8 = r0 + br.ret.sptk.many b0 + .endp q_atomic_test_and_set_int# + .align 16 + .global q_atomic_test_and_set_ptr# + .proc q_atomic_test_and_set_ptr# +q_atomic_test_and_set_ptr: + .prologue + .body + mov ar.ccv=r33 + ;; + cmpxchg8.acq r34=[r32],r34,ar.ccv + ;; + cmp.eq p6, p7 = r33, r34 + ;; + (p6) addl r8 = 1, r0 + (p7) mov r8 = r0 + br.ret.sptk.many b0 + .endp q_atomic_test_and_set_ptr# diff --git a/src/corelib/arch/integrity/arch.pri b/src/corelib/arch/integrity/arch.pri new file mode 100644 index 0000000000..2c4196ec32 --- /dev/null +++ b/src/corelib/arch/integrity/arch.pri @@ -0,0 +1,3 @@ +# +# INTEGRITY RTOS architecture +# diff --git a/src/corelib/arch/macosx/arch.pri b/src/corelib/arch/macosx/arch.pri new file mode 100644 index 0000000000..a2b1bf759a --- /dev/null +++ b/src/corelib/arch/macosx/arch.pri @@ -0,0 +1,6 @@ +# +# Mac OS X architecture +# + +# Left blank intentionally since all the current compilers that we support can +# handle in-line assembly. diff --git a/src/corelib/arch/macosx/qatomic32_ppc.s b/src/corelib/arch/macosx/qatomic32_ppc.s new file mode 100644 index 0000000000..c9a318dccd --- /dev/null +++ b/src/corelib/arch/macosx/qatomic32_ppc.s @@ -0,0 +1,169 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .section __TEXT,__text,regular,pure_instructions + .section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .section __TEXT,__text,regular,pure_instructions + .align 2 + .align 2 + .globl _q_atomic_test_and_set_int + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_test_and_set_int: + lwarx r6,0,r3 + cmpw r6,r4 + bne- $+20 + stwcx. r5,0,r3 + bne- $-16 + addi r3,0,1 + blr + addi r3,0,0 + blr + + .align 2 + .globl _q_atomic_test_and_set_acquire_int + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_test_and_set_acquire_int: + lwarx r6,0,r3 + cmpw r6,r4 + bne- $+20 + stwcx. r5,0,r3 + bne- $-16 + addi r3,0,1 + b $+8 + addi r3,0,0 + eieio + blr + + .align 2 + .globl _q_atomic_test_and_set_release_int + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_test_and_set_release_int: + eieio + lwarx r6,0,r3 + cmpw r6,r4 + bne- $+20 + stwcx. r5,0,r3 + bne- $-16 + addi r3,0,1 + blr + addi r3,0,0 + blr + + .align 2 + .globl _q_atomic_test_and_set_ptr + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_test_and_set_ptr: + lwarx r6,0,r3 + cmpw r6,r4 + bne- $+20 + stwcx. r5,0,r3 + bne- $-16 + addi r3,0,1 + blr + addi r3,0,0 + blr + + .align 2 + .globl _q_atomic_increment + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_increment: + lwarx r4,0,r3 + addi r4,r4,1 + stwcx. r4,0,r3 + bne- $-12 + mr r3,r4 + blr + + .align 2 + .globl _q_atomic_decrement + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_decrement: + lwarx r4,0,r3 + subi r4,r4,1 + stwcx. r4,0,r3 + bne- $-12 + mr r3,r4 + blr + + .align 2 + .globl _q_atomic_set_int + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_set_int: + lwarx r5,0,r3 + stwcx. r4,0,r3 + bne- $-8 + mr r3,r5 + blr + + .align 2 + .globl _q_atomic_set_ptr + .section __TEXT,__text,regular,pure_instructions + .align 2 +_q_atomic_set_ptr: + lwarx r5,0,r3 + stwcx. r4,0,r3 + bne- $-8 + mr r3,r5 + blr + +.globl q_atomic_test_and_set_int.eh + q_atomic_test_and_set_int.eh = 0 +.globl q_atomic_test_and_set_ptr.eh + q_atomic_test_and_set_ptr.eh = 0 +.globl q_atomic_increment.eh + q_atomic_increment.eh = 0 +.globl q_atomic_decrement.eh + q_atomic_decrement.eh = 0 +.globl q_atomic_set_int.eh + q_atomic_set_int.eh = 0 +.globl q_atomic_set_ptr.eh + q_atomic_set_ptr.eh = 0 +.data +.constructor +.data +.destructor +.align 1 diff --git a/src/corelib/arch/mips/arch.pri b/src/corelib/arch/mips/arch.pri new file mode 100644 index 0000000000..296c845ab3 --- /dev/null +++ b/src/corelib/arch/mips/arch.pri @@ -0,0 +1,8 @@ +# +# MIPS 3/4 architecture +# + +# note: even though we use inline assembler with gcc, we always +# include the compiled version to keep binary compatibility +*-64:SOURCES += $$QT_ARCH_CPP/qatomic_mips64.s +else:SOURCES += $$QT_ARCH_CPP/qatomic_mips32.s diff --git a/src/corelib/arch/mips/qatomic_mips32.s b/src/corelib/arch/mips/qatomic_mips32.s new file mode 100644 index 0000000000..d4c0191cfa --- /dev/null +++ b/src/corelib/arch/mips/qatomic_mips32.s @@ -0,0 +1,150 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .set nobopt + .set noreorder + .option pic2 + .text + + .globl q_atomic_test_and_set_int + .ent q_atomic_test_and_set_int + .set mips2 +q_atomic_test_and_set_int: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_int + + .globl q_atomic_test_and_set_acquire_int + .ent q_atomic_test_and_set_acquire_int + .set mips2 +q_atomic_test_and_set_acquire_int: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: sync + jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_acquire_int + + .globl q_atomic_test_and_set_release_int + .ent q_atomic_test_and_set_release_int + .set mips2 +q_atomic_test_and_set_release_int: + sync +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_release_int + + .globl q_atomic_test_and_set_ptr + .ent q_atomic_test_and_set_ptr + .set mips2 +q_atomic_test_and_set_ptr: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_ptr + + .globl q_atomic_test_and_set_acquire_ptr + .ent q_atomic_test_and_set_acquire_ptr + .set mips2 +q_atomic_test_and_set_acquire_ptr: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: sync + jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_acquire_ptr + + .globl q_atomic_test_and_set_release_ptr + .ent q_atomic_test_and_set_release_ptr + .set mips2 +q_atomic_test_and_set_release_ptr: + sync +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .set mips0 + .end q_atomic_test_and_set_release_ptr diff --git a/src/corelib/arch/mips/qatomic_mips64.s b/src/corelib/arch/mips/qatomic_mips64.s new file mode 100644 index 0000000000..993991f0b7 --- /dev/null +++ b/src/corelib/arch/mips/qatomic_mips64.s @@ -0,0 +1,138 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .set nobopt + .set noreorder + .option pic2 + .text + + .globl q_atomic_test_and_set_int + .ent q_atomic_test_and_set_int +q_atomic_test_and_set_int: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .end q_atomic_test_and_set_int + + .globl q_atomic_test_and_set_acquire_int + .ent q_atomic_test_and_set_acquire_int +q_atomic_test_and_set_acquire_int: +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: sync + jr $31 + move $2,$0 + .end q_atomic_test_and_set_acquire_int + + .globl q_atomic_test_and_set_release_int + .ent q_atomic_test_and_set_release_int +q_atomic_test_and_set_release_int: + sync +1: ll $8,0($4) + bne $8,$5,2f + move $2,$6 + sc $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .end q_atomic_test_and_set_release_int + + .globl q_atomic_test_and_set_ptr + .ent q_atomic_test_and_set_ptr +q_atomic_test_and_set_ptr: +1: lld $8,0($4) + bne $8,$5,2f + move $2,$6 + scd $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .end q_atomic_test_and_set_ptr + + .globl q_atomic_test_and_set_acquire_ptr + .ent q_atomic_test_and_set_acquire_ptr +q_atomic_test_and_set_acquire_ptr: +1: lld $8,0($4) + bne $8,$5,2f + move $2,$6 + scd $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: sync + jr $31 + move $2,$0 + .end q_atomic_test_and_set_acquire_ptr + + .globl q_atomic_test_and_set_release_ptr + .ent q_atomic_test_and_set_release_ptr +q_atomic_test_and_set_release_ptr: + sync +1: lld $8,0($4) + bne $8,$5,2f + move $2,$6 + scd $2,0($4) + beqz $2,1b + nop + jr $31 + nop +2: jr $31 + move $2,$0 + .end q_atomic_test_and_set_release_ptr diff --git a/src/corelib/arch/parisc/arch.pri b/src/corelib/arch/parisc/arch.pri new file mode 100644 index 0000000000..fab2897f04 --- /dev/null +++ b/src/corelib/arch/parisc/arch.pri @@ -0,0 +1,5 @@ +# +# HP PA-RISC architecture +# +SOURCES += $$QT_ARCH_CPP/q_ldcw.s \ + $$QT_ARCH_CPP/qatomic_parisc.cpp diff --git a/src/corelib/arch/parisc/q_ldcw.s b/src/corelib/arch/parisc/q_ldcw.s new file mode 100644 index 0000000000..f8f40467ec --- /dev/null +++ b/src/corelib/arch/parisc/q_ldcw.s @@ -0,0 +1,62 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +;** All rights reserved. +;** Contact: Nokia Corporation (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the Technology Preview License Agreement accompanying +;** this package. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain additional +;** rights. These rights are described in the Nokia Qt LGPL Exception +;** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +;** +;** If you have questions regarding the use of this file, please contact +;** Nokia at qt-info@nokia.com. +;** +;** +;** +;** +;** +;** +;** +;** +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + .SPACE $PRIVATE$ + .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31 + .SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82 + .SPACE $TEXT$ + .SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44 + .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY + .IMPORT $global$,DATA + .IMPORT $$dyncall,MILLICODE + .SPACE $TEXT$ + .SUBSPA $CODE$ + + .align 4 + .EXPORT q_ldcw,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR +q_ldcw + .PROC + .CALLINFO FRAME=0,CALLS,SAVE_RP + .ENTRY + ldcw 0(%r26),%r1 + bv %r0(%r2) + copy %r1,%r28 + .EXIT + .PROCEND diff --git a/src/corelib/arch/parisc/qatomic_parisc.cpp b/src/corelib/arch/parisc/qatomic_parisc.cpp new file mode 100644 index 0000000000..fa446c5d7b --- /dev/null +++ b/src/corelib/arch/parisc/qatomic_parisc.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +#define UNLOCKED {-1,-1,-1,-1} +#define UNLOCKED2 UNLOCKED,UNLOCKED +#define UNLOCKED4 UNLOCKED2,UNLOCKED2 +#define UNLOCKED8 UNLOCKED4,UNLOCKED4 +#define UNLOCKED16 UNLOCKED8,UNLOCKED8 +#define UNLOCKED32 UNLOCKED16,UNLOCKED16 +#define UNLOCKED64 UNLOCKED32,UNLOCKED32 +#define UNLOCKED128 UNLOCKED64,UNLOCKED64 +#define UNLOCKED256 UNLOCKED128,UNLOCKED128 + +// use a 4k page for locks +static int locks[256][4] = { UNLOCKED256 }; + +int *getLock(volatile void *addr) +{ return locks[qHash(const_cast(addr)) % 256]; } + +static int *align16(int *lock) +{ + ulong off = (((ulong) lock) % 16); + return off ? (int *)(ulong(lock) + 16 - off) : lock; +} + +extern "C" { + + int q_ldcw(volatile int *addr); + + void q_atomic_lock(int *lock) + { + // ldcw requires a 16-byte aligned address + volatile int *x = align16(lock); + while (q_ldcw(x) == 0) + ; + } + + void q_atomic_unlock(int *lock) + { lock[0] = lock[1] = lock[2] = lock[3] = -1; } +} + + +QT_END_NAMESPACE diff --git a/src/corelib/arch/powerpc/arch.pri b/src/corelib/arch/powerpc/arch.pri new file mode 100644 index 0000000000..1989ac73a7 --- /dev/null +++ b/src/corelib/arch/powerpc/arch.pri @@ -0,0 +1,10 @@ +# +# PowerPC architecture +# +!*-g++* { + *-64 { + SOURCES += $$QT_ARCH_CPP/qatomic64.s + } else { + SOURCES += $$QT_ARCH_CPP/qatomic32.s + } +} diff --git a/src/corelib/arch/powerpc/qatomic32.s b/src/corelib/arch/powerpc/qatomic32.s new file mode 100644 index 0000000000..a446359e25 --- /dev/null +++ b/src/corelib/arch/powerpc/qatomic32.s @@ -0,0 +1,525 @@ +############################################################################ +## +## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the QtGui module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################ + .machine "ppc" + .toc + .csect .text[PR] + + .align 2 + .globl q_atomic_test_and_set_int + .globl .q_atomic_test_and_set_int + .csect q_atomic_test_and_set_int[DS],3 +q_atomic_test_and_set_int: + .long .q_atomic_test_and_set_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_int-.q_atomic_test_and_set_int + .short 25 + .byte "q_atomic_test_and_set_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_int + .globl .q_atomic_test_and_set_acquire_int + .csect q_atomic_test_and_set_acquire_int[DS],3 +q_atomic_test_and_set_acquire_int: + .long .q_atomic_test_and_set_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_acquire_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+16 + stwcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_int-.q_atomic_test_and_set_acquire_int + .short 33 + .byte "q_atomic_test_and_set_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_int + .globl .q_atomic_test_and_set_release_int + .csect q_atomic_test_and_set_release_int[DS],3 +q_atomic_test_and_set_release_int: + .long .q_atomic_test_and_set_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_release_int: + eieio + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_release_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_int-.q_atomic_test_and_set_release_int + .short 33 + .byte "q_atomic_test_and_set_release_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_ptr + .globl .q_atomic_test_and_set_ptr + .csect q_atomic_test_and_set_ptr[DS],3 +q_atomic_test_and_set_ptr: + .long .q_atomic_test_and_set_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_ptr: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_ptr-.q_atomic_test_and_set_ptr + .short 25 + .byte "q_atomic_test_and_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_ptr + .globl .q_atomic_test_and_set_acquire_ptr + .csect q_atomic_test_and_set_acquire_ptr[DS],3 +q_atomic_test_and_set_acquire_ptr: + .long .q_atomic_test_and_set_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_acquire_ptr: + lwarx 6,0,3 + xor. 6,6,4 + bne $+16 + stwcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_ptr-.q_atomic_test_and_set_acquire_ptr + .short 25 + .byte "q_atomic_test_and_set_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_ptr + .globl .q_atomic_test_and_set_release_ptr + .csect q_atomic_test_and_set_release_ptr[DS],3 +q_atomic_test_and_set_release_ptr: + .long .q_atomic_test_and_set_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_release_ptr: + eieio + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_ptr-.q_atomic_test_and_set_release_ptr + .short 33 + .byte "q_atomic_test_and_set_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_increment + .globl .q_atomic_increment + .csect q_atomic_increment[DS],3 +q_atomic_increment: + .long .q_atomic_increment,TOC[tc0],0 + .csect .text[PR] +.q_atomic_increment: + lwarx 4,0,3 + addi 4,4,1 + stwcx. 4,0,3 + bne- $-12 + mr 3,4 + blr +LT..q_atomic_increment: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_increment-.q_atomic_increment + .short 18 + .byte "q_atomic_increment" + .align 2 + + .align 2 + .globl q_atomic_decrement + .globl .q_atomic_decrement + .csect q_atomic_decrement[DS],3 +q_atomic_decrement: + .long .q_atomic_decrement,TOC[tc0],0 + .csect .text[PR] +.q_atomic_decrement: + lwarx 4,0,3 + subi 4,4,1 + stwcx. 4,0,3 + bne- $-12 + mr 3,4 + blr +LT..q_atomic_decrement: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_decrement-.q_atomic_decrement + .short 18 + .byte "q_atomic_decrement" + .align 2 + + .align 2 + .globl q_atomic_set_int + .globl .q_atomic_set_int + .csect q_atomic_set_int[DS],3 +q_atomic_set_int: + .long .q_atomic_set_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_set_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_set_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_int-.q_atomic_set_int + .short 16 + .byte "q_atomic_set_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_int + .globl .q_atomic_fetch_and_store_acquire_int + .csect q_atomic_fetch_and_store_acquire_int[DS],3 +q_atomic_fetch_and_store_acquire_int: + .long .q_atomic_fetch_and_store_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_acquire_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_int-.q_atomic_fetch_and_store_acquire_int + .short 16 + .byte "q_atomic_fetch_and_store_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_int + .globl .q_atomic_fetch_and_store_release_int + .csect q_atomic_fetch_and_store_release_int[DS],3 +q_atomic_fetch_and_store_release_int: + .long .q_atomic_fetch_and_store_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_release_int: + eieio + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_fetch_and_store_release_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_int-.q_atomic_fetch_and_store_release_int + .short 16 + .byte "q_atomic_fetch_and_store_release_int" + .align 2 + + .align 2 + .globl q_atomic_set_ptr + .globl .q_atomic_set_ptr + .csect q_atomic_set_ptr[DS],3 +q_atomic_set_ptr: + .long .q_atomic_set_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_set_ptr: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_ptr-.q_atomic_set_ptr + .short 16 + .byte "q_atomic_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_ptr + .globl .q_atomic_fetch_and_store_acquire_ptr + .csect q_atomic_fetch_and_store_acquire_ptr[DS],3 +q_atomic_fetch_and_store_acquire_ptr: + .long .q_atomic_fetch_and_store_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_acquire_ptr: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_ptr-.q_atomic_fetch_and_store_acquire_ptr + .short 16 + .byte "q_atomic_fetch_and_store_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_ptr + .globl .q_atomic_fetch_and_store_release_ptr + .csect q_atomic_fetch_and_store_release_ptr[DS],3 +q_atomic_fetch_and_store_release_ptr: + .long .q_atomic_fetch_and_store_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_release_ptr: + eieio + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_fetch_and_store_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_ptr-.q_atomic_fetch_and_store_release_ptr + .short 16 + .byte "q_atomic_fetch_and_store_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_int + .globl .q_atomic_fetch_and_add_int + .csect q_atomic_fetch_and_add_int[DS],3 +q_atomic_fetch_and_add_int: + .long .q_atomic_fetch_and_add_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_int: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_int-.q_atomic_fetch_and_add_int + .short 18 + .byte "q_atomic_fetch_and_add_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_int + .globl .q_atomic_fetch_and_add_acquire_int + .csect q_atomic_fetch_and_add_acquire_int[DS],3 +q_atomic_fetch_and_add_acquire_int: + .long .q_atomic_fetch_and_add_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_acquire_int: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_int-.q_atomic_fetch_and_add_acquire_int + .short 18 + .byte "q_atomic_fetch_and_add_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_int + .globl .q_atomic_fetch_and_add_release_int + .csect q_atomic_fetch_and_add_release_int[DS],3 +q_atomic_fetch_and_add_release_int: + .long .q_atomic_fetch_and_add_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_release_int: + eieio + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_release_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_int-.q_atomic_fetch_and_add_release_int + .short 34 + .byte "q_atomic_fetch_and_add_release_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_ptr + .globl .q_atomic_fetch_and_add_ptr + .csect q_atomic_fetch_and_add_ptr[DS],3 +q_atomic_fetch_and_add_ptr: + .long .q_atomic_fetch_and_add_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_ptr: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_ptr-.q_atomic_fetch_and_add_ptr + .short 26 + .byte "q_atomic_fetch_and_add_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_ptr + .globl .q_atomic_fetch_and_add_acquire_ptr + .csect q_atomic_fetch_and_add_acquire_ptr[DS],3 +q_atomic_fetch_and_add_acquire_ptr: + .long .q_atomic_fetch_and_add_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_acquire_ptr: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_ptr-.q_atomic_fetch_and_add_acquire_ptr + .short 34 + .byte "q_atomic_fetch_and_add_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_ptr + .globl .q_atomic_fetch_and_add_release_ptr + .csect q_atomic_fetch_and_add_release_ptr[DS],3 +q_atomic_fetch_and_add_release_ptr: + .long .q_atomic_fetch_and_add_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_release_ptr: + eieio + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_ptr-.q_atomic_fetch_and_add_release_ptr + .short 34 + .byte "q_atomic_fetch_and_add_release_ptr" + .align 2 + +_section_.text: + .csect .data[RW],3 + .long _section_.text diff --git a/src/corelib/arch/powerpc/qatomic64.s b/src/corelib/arch/powerpc/qatomic64.s new file mode 100644 index 0000000000..9bf31912a1 --- /dev/null +++ b/src/corelib/arch/powerpc/qatomic64.s @@ -0,0 +1,533 @@ +############################################################################ +## +## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +## All rights reserved. +## Contact: Nokia Corporation (qt-info@nokia.com) +## +## This file is part of the QtGui module of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:LGPL$ +## No Commercial Usage +## This file contains pre-release code and may not be distributed. +## You may use this file in accordance with the terms and conditions +## contained in the Technology Preview License Agreement accompanying +## this package. +## +## GNU Lesser General Public License Usage +## Alternatively, this file may be used under the terms of the GNU Lesser +## General Public License version 2.1 as published by the Free Software +## Foundation and appearing in the file LICENSE.LGPL included in the +## packaging of this file. Please review the following information to +## ensure the GNU Lesser General Public License version 2.1 requirements +## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +## +## In addition, as a special exception, Nokia gives you certain additional +## rights. These rights are described in the Nokia Qt LGPL Exception +## version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +## +## If you have questions regarding the use of this file, please contact +## Nokia at qt-info@nokia.com. +## +## +## +## +## +## +## +## +## $QT_END_LICENSE$ +## +############################################################################ + .machine "ppc64" + .toc + .csect .text[PR] + + .align 2 + .globl q_atomic_test_and_set_int + .globl .q_atomic_test_and_set_int + .csect q_atomic_test_and_set_int[DS],3 +q_atomic_test_and_set_int: + .llong .q_atomic_test_and_set_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + extsw 3,3 + blr +LT..q_atomic_test_and_set_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_int-.q_atomic_test_and_set_int + .short 25 + .byte "q_atomic_test_and_set_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_int + .globl .q_atomic_test_and_set_acquire_int + .csect q_atomic_test_and_set_acquire_int[DS],3 +q_atomic_test_and_set_acquire_int: + .llong .q_atomic_test_and_set_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_acquire_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+16 + stwcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + extsw 3,3 + blr +LT..q_atomic_test_and_set_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_int-.q_atomic_test_and_set_acquire_int + .short 33 + .byte "q_atomic_test_and_set_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_int + .globl .q_atomic_test_and_set_release_int + .csect q_atomic_test_and_set_release_int[DS],3 +q_atomic_test_and_set_release_int: + .llong .q_atomic_test_and_set_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_release_int: + eieio + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + extsw 3,3 + blr +LT..q_atomic_test_and_set_release_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_int-.q_atomic_test_and_set_release_int + .short 33 + .byte "q_atomic_test_and_set_release_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_ptr + .globl .q_atomic_test_and_set_ptr + .csect q_atomic_test_and_set_ptr[DS],3 +q_atomic_test_and_set_ptr: + .llong .q_atomic_test_and_set_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_ptr: + ldarx 6,0,3 + xor. 6,6,4 + bne $+12 + stdcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_ptr-.q_atomic_test_and_set_ptr + .short 25 + .byte "q_atomic_test_and_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_ptr + .globl .q_atomic_test_and_set_acquire_ptr + .csect q_atomic_test_and_set_acquire_ptr[DS],3 +q_atomic_test_and_set_acquire_ptr: + .llong .q_atomic_test_and_set_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_acquire_ptr: + ldarx 6,0,3 + xor. 6,6,4 + bne $+16 + stdcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_ptr-.q_atomic_test_and_set_acquire_ptr + .short 33 + .byte "q_atomic_test_and_set_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_ptr + .globl .q_atomic_test_and_set_release_ptr + .csect q_atomic_test_and_set_release_ptr[DS],3 +q_atomic_test_and_set_release_ptr: + .llong .q_atomic_test_and_set_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_test_and_set_release_ptr: + eieio + ldarx 6,0,3 + xor. 6,6,4 + bne $+12 + stdcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_ptr-.q_atomic_test_and_set_release_ptr + .short 33 + .byte "q_atomic_test_and_set_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_increment + .globl .q_atomic_increment + .csect q_atomic_increment[DS],3 +q_atomic_increment: + .llong .q_atomic_increment,TOC[tc0],0 + .csect .text[PR] +.q_atomic_increment: + lwarx 4,0,3 + addi 5,4,1 + extsw 4,5 + stwcx. 4,0,3 + bne- $-16 + mr 3,4 + blr +LT..q_atomic_increment: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_increment-.q_atomic_increment + .short 18 + .byte "q_atomic_increment" + .align 2 + + .align 2 + .globl q_atomic_decrement + .globl .q_atomic_decrement + .csect q_atomic_decrement[DS],3 +q_atomic_decrement: + .llong .q_atomic_decrement,TOC[tc0],0 + .csect .text[PR] +.q_atomic_decrement: + lwarx 4,0,3 + subi 5,4,1 + extsw 4,5 + stwcx. 4,0,3 + bne- $-16 + mr 3,4 + blr +LT..q_atomic_decrement: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_decrement-.q_atomic_decrement + .short 18 + .byte "q_atomic_decrement" + .align 2 + + .align 2 + .globl q_atomic_set_int + .globl .q_atomic_set_int + .csect q_atomic_set_int[DS],3 +q_atomic_set_int: + .llong .q_atomic_set_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_set_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + extsw 3,5 + blr +LT..q_atomic_set_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_int-.q_atomic_set_int + .short 16 + .byte "q_atomic_set_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_int + .globl .q_atomic_fetch_and_store_acquire_int + .csect q_atomic_fetch_and_store_acquire_int[DS],3 +q_atomic_fetch_and_store_acquire_int: + .llong .q_atomic_fetch_and_store_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_acquire_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + isync + extsw 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_int-.q_atomic_fetch_and_store_acquire_int + .short 36 + .byte "q_atomic_fetch_and_store_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_int + .globl .q_atomic_fetch_and_store_release_int + .csect q_atomic_fetch_and_store_release_int[DS],3 +q_atomic_fetch_and_store_release_int: + .llong .q_atomic_fetch_and_store_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_release_int: + eieio + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + extsw 3,5 + blr +LT..q_atomic_fetch_and_store_release_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_int-.q_atomic_fetch_and_store_release_int + .short 36 + .byte "q_atomic_fetch_and_store_release_int" + .align 2 + + .align 2 + .globl q_atomic_set_ptr + .globl .q_atomic_set_ptr + .csect q_atomic_set_ptr[DS],3 +q_atomic_set_ptr: + .llong .q_atomic_set_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_set_ptr: + ldarx 5,0,3 + stdcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_ptr-.q_atomic_set_ptr + .short 16 + .byte "q_atomic_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_ptr + .globl .q_atomic_fetch_and_store_acquire_ptr + .csect q_atomic_fetch_and_store_acquire_ptr[DS],3 +q_atomic_fetch_and_store_acquire_ptr: + .llong .q_atomic_fetch_and_store_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_acquire_ptr: + ldarx 5,0,3 + stdcx. 4,0,3 + bne- $-8 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_ptr-.q_atomic_fetch_and_store_acquire_ptr + .short 36 + .byte "q_atomic_fetch_and_store_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_ptr + .globl .q_atomic_fetch_and_store_release_ptr + .csect q_atomic_fetch_and_store_release_ptr[DS],3 +q_atomic_fetch_and_store_release_ptr: + .llong .q_atomic_fetch_and_store_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_store_release_ptr: + eieio + ldarx 5,0,3 + stdcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_fetch_and_store_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_ptr-.q_atomic_fetch_and_store_release_ptr + .short 36 + .byte "q_atomic_fetch_and_store_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_int + .globl .q_atomic_fetch_and_add_int + .csect q_atomic_fetch_and_add_int[DS],3 +q_atomic_fetch_and_add_int: + .llong .q_atomic_fetch_and_add_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_int: + lwarx 5,0,3 + add 6,4,5 + extsw 7,6 + stwcx. 7,0,3 + bne- $-16 + extsw 3,5 + blr +LT..q_atomic_fetch_and_add_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_int-.q_atomic_fetch_and_add_int + .short 26 + .byte "q_atomic_fetch_and_add_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_int + .globl .q_atomic_fetch_and_add_acquire_int + .csect q_atomic_fetch_and_add_acquire_int[DS],3 +q_atomic_fetch_and_add_acquire_int: + .llong .q_atomic_fetch_and_add_acquire_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_acquire_int: + lwarx 5,0,3 + add 6,4,5 + extsw 7,6 + stwcx. 7,0,3 + bne- $-16 + isync + extsw 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_int-.q_atomic_fetch_and_add_acquire_int + .short 34 + .byte "q_atomic_fetch_and_add_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_int + .globl .q_atomic_fetch_and_add_release_int + .csect q_atomic_fetch_and_add_release_int[DS],3 +q_atomic_fetch_and_add_release_int: + .llong .q_atomic_fetch_and_add_release_int,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_release_int: + eieio + lwarx 5,0,3 + add 6,4,5 + extsw 7,6 + stwcx. 7,0,3 + bne- $-16 + extsw 3,5 + blr +LT..q_atomic_fetch_and_add_release_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_int-.q_atomic_fetch_and_add_release_int + .short 34 + .byte "q_atomic_fetch_and_add_release_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_ptr + .globl .q_atomic_fetch_and_add_ptr + .csect q_atomic_fetch_and_add_ptr[DS],3 +q_atomic_fetch_and_add_ptr: + .llong .q_atomic_fetch_and_add_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_ptr: + ldarx 5,0,3 + add 6,4,5 + stdcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_ptr-.q_atomic_fetch_and_add_ptr + .short 26 + .byte "q_atomic_fetch_and_add_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_ptr + .globl .q_atomic_fetch_and_add_acquire_ptr + .csect q_atomic_fetch_and_add_acquire_ptr[DS],3 +q_atomic_fetch_and_add_acquire_ptr: + .llong .q_atomic_fetch_and_add_acquire_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_acquire_ptr: + ldarx 5,0,3 + add 6,4,5 + stdcx. 6,0,3 + bne- $-12 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_ptr-.q_atomic_fetch_and_add_acquire_ptr + .short 34 + .byte "q_atomic_fetch_and_add_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_ptr + .globl .q_atomic_fetch_and_add_release_ptr + .csect q_atomic_fetch_and_add_release_ptr[DS],3 +q_atomic_fetch_and_add_release_ptr: + .llong .q_atomic_fetch_and_add_release_ptr,TOC[tc0],0 + .csect .text[PR] +.q_atomic_fetch_and_add_release_ptr: + eieio + ldarx 5,0,3 + add 6,4,5 + stdcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_ptr-.q_atomic_fetch_and_add_release_ptr + .short 34 + .byte "q_atomic_fetch_and_add_release_ptr" + .align 2 + +_section_.text: + .csect .data[RW],3 + .llong _section_.text diff --git a/src/corelib/arch/qatomic_alpha.h b/src/corelib/arch/qatomic_alpha.h new file mode 100644 index 0000000000..be5d7ec884 --- /dev/null +++ b/src/corelib/arch/qatomic_alpha.h @@ -0,0 +1,642 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ALPHA_H +#define QATOMIC_ALPHA_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#if defined(Q_CC_GNU) + +inline bool QBasicAtomicInt::ref() +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "addl %0,1,%1\n" /* tmp=old+1; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : + : "memory"); + return old != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "subl %0,1,%1\n" /* tmp=old-1; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : + : "memory"); + return old != 1; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int ret; + asm volatile("1:\n" + "ldl_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) ret=0; else ret=1; */ + "beq %0,3f\n" /* if (ret==0) goto 3; */ + "mov %3,%0\n" /* ret=newval; */ + "stl_c %0,%1\n" /* if ((*ptr=ret)!=ret) ret=0; else ret=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + register int ret; + asm volatile("1:\n" + "ldl_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) ret=0; else ret=1; */ + "beq %0,3f\n" /* if (ret==0) goto 3; */ + "mov %3,%0\n" /* ret=newval; */ + "stl_c %0,%1\n" /* if ((*ptr=ret)!=ret) ret=0; else ret=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + register int ret; + asm volatile("mb\n" + "1:\n" + "ldl_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) ret=0; else ret=1; */ + "beq %0,3f\n" /* if (ret==0) goto 3; */ + "mov %3,%0\n" /* ret=newval; */ + "stl_c %0,%1\n" /* if ((*ptr=ret)!=ret) ret=0; else ret=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + register int old, tmp; + asm volatile("mb\n" + "1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "addl %0,%3,%1\n"/* tmp=old+value; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return old; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + register int old, tmp; + asm volatile("1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "addl %0,%3,%1\n"/* tmp=old+value; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return old; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + register int old, tmp; + asm volatile("mb\n" + "1:\n" + "ldl_l %0,%2\n" /* old=*ptr; */ + "addl %0,%3,%1\n"/* tmp=old+value; */ + "stl_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return old; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register void *ret; + asm volatile("1:\n" + "ldq_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) tmp=0; else tmp=1; */ + "beq %0,3f\n" /* if (tmp==0) goto 3; */ + "mov %3,%0\n" /* tmp=newval; */ + "stq_c %0,%1\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + register void *ret; + asm volatile("1:\n" + "ldq_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) tmp=0; else tmp=1; */ + "beq %0,3f\n" /* if (tmp==0) goto 3; */ + "mov %3,%0\n" /* tmp=newval; */ + "stq_c %0,%1\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + register void *ret; + asm volatile("mb\n" + "1:\n" + "ldq_l %0,%1\n" /* ret=*ptr; */ + "cmpeq %0,%2,%0\n"/* if (ret==expected) tmp=0; else tmp=1; */ + "beq %0,3f\n" /* if (tmp==0) goto 3; */ + "mov %3,%0\n" /* tmp=newval; */ + "stq_c %0,%1\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %0,2f\n" /* if (ret==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *old, *tmp; + asm volatile("1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + register T *old, *tmp; + asm volatile("1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + register T *old, *tmp; + asm volatile("mb\n" + "1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "mov %3,%1\n" /* tmp=newval; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp==0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return old; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *old, *tmp; + asm volatile("1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "addq %0,%3,%1\n"/* tmp=old+value; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return reinterpret_cast(old); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + register T *old, *tmp; + asm volatile("1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "addq %0,%3,%1\n"/* tmp=old+value; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + "mb\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return reinterpret_cast(old); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + register T *old, *tmp; + asm volatile("mb\n" + "1:\n" + "ldq_l %0,%2\n" /* old=*ptr; */ + "addq %0,%3,%1\n"/* tmp=old+value; */ + "stq_c %1,%2\n" /* if ((*ptr=tmp)!=tmp) tmp=0; else tmp=1; */ + "beq %1,2f\n" /* if (tmp == 0) goto 2; */ + "br 3f\n" /* goto 3; */ + "2: br 1b\n" /* goto 1; */ + "3:\n" + : "=&r" (old), "=&r" (tmp), "+m"(_q_value) + : "r" (valueToAdd) + : "memory"); + return reinterpret_cast(old); +} + +#else // !Q_CC_GNU + +extern "C" { + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_acquire_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_release_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_increment(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_decrement(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval); + Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval); + Q_CORE_EXPORT int q_atomic_fetch_and_add_int(volatile int *ptr, int value); + Q_CORE_EXPORT int q_atomic_fetch_and_add_acquire_int(volatile int *ptr, int value); + Q_CORE_EXPORT int q_atomic_fetch_and_add_release_int(volatile int *ptr, int value); +} // extern "C" + +inline bool QBasicAtomicInt::ref() +{ + return q_atomic_increment(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return q_atomic_decrement(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_release_int(&_q_value, expectedValue, newValue) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return q_atomic_set_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return q_atomic_fetch_and_store_acquire_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return q_atomic_fetch_and_store_release_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return q_atomic_fetch_and_add_int(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return q_atomic_fetch_and_add_acquire_int(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return q_atomic_fetch_and_add_release_int(&_q_value, valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_release_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_acquire_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_release_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_ptr(&_q_value, newValue)); +} +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_acquire_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_release_ptr(&_q_value, newValue)); +} + +#endif // Q_CC_GNU + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_ALPHA_H diff --git a/src/corelib/arch/qatomic_arch.h b/src/corelib/arch/qatomic_arch.h new file mode 100644 index 0000000000..3da833a424 --- /dev/null +++ b/src/corelib/arch/qatomic_arch.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ARCH_H +#define QATOMIC_ARCH_H + +QT_BEGIN_HEADER + +#include "QtCore/qglobal.h" + +#if defined(QT_ARCH_INTEGRITY) +# include "QtCore/qatomic_integrity.h" +#elif defined(QT_ARCH_VXWORKS) +# include "QtCore/qatomic_vxworks.h" +#elif defined(QT_ARCH_ALPHA) +# include "QtCore/qatomic_alpha.h" +#elif defined(QT_ARCH_ARM) +# include "QtCore/qatomic_arm.h" +#elif defined(QT_ARCH_ARMV6) +# include "QtCore/qatomic_armv6.h" +#elif defined(QT_ARCH_AVR32) +# include "QtCore/qatomic_avr32.h" +#elif defined(QT_ARCH_BFIN) +# include "QtCore/qatomic_bfin.h" +#elif defined(QT_ARCH_GENERIC) +# include "QtCore/qatomic_generic.h" +#elif defined(QT_ARCH_I386) +# include "QtCore/qatomic_i386.h" +#elif defined(QT_ARCH_IA64) +# include "QtCore/qatomic_ia64.h" +#elif defined(QT_ARCH_MACOSX) +# include "QtCore/qatomic_macosx.h" +#elif defined(QT_ARCH_MIPS) +# include "QtCore/qatomic_mips.h" +#elif defined(QT_ARCH_PARISC) +# include "QtCore/qatomic_parisc.h" +#elif defined(QT_ARCH_POWERPC) +# include "QtCore/qatomic_powerpc.h" +#elif defined(QT_ARCH_S390) +# include "QtCore/qatomic_s390.h" +#elif defined(QT_ARCH_SPARC) +# include "QtCore/qatomic_sparc.h" +#elif defined(QT_ARCH_WINDOWS) +# include "QtCore/qatomic_windows.h" +#elif defined(QT_ARCH_WINDOWSCE) +# include "QtCore/qatomic_windowsce.h" +#elif defined(QT_ARCH_X86_64) +# include "QtCore/qatomic_x86_64.h" +#elif defined(QT_ARCH_SYMBIAN) +# include "QtCore/qatomic_symbian.h" +#elif defined(QT_ARCH_SH) +# include "QtCore/qatomic_sh.h" +#elif defined(QT_ARCH_SH4A) +# include "QtCore/qatomic_sh4a.h" +#elif defined(QT_ARCH_NACL) +# include "QtCore/qatomic_generic.h" +#else +# error "Qt has not been ported to this architecture" +#endif + +QT_END_HEADER + +#endif // QATOMIC_ARCH_H diff --git a/src/corelib/arch/qatomic_arm.h b/src/corelib/arch/qatomic_arm.h new file mode 100644 index 0000000000..07d21438d6 --- /dev/null +++ b/src/corelib/arch/qatomic_arm.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ARM_H +#define QATOMIC_ARM_H + +QT_BEGIN_HEADER + +#if defined(__ARM_ARCH_7__) \ + || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) \ + || defined(__ARM_ARCH_7M__) +# define QT_ARCH_ARMV7 +QT_BEGIN_INCLUDE_HEADER +# include "QtCore/qatomic_armv7.h" +QT_END_INCLUDE_HEADER +#elif defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6M__) \ + || (defined(__TARGET_ARCH_ARM) && (__TARGET_ARCH_ARM-0 >= 6)) +# define QT_ARCH_ARMV6 +QT_BEGIN_INCLUDE_HEADER +# include "QtCore/qatomic_armv6.h" +QT_END_INCLUDE_HEADER +#else +# define QT_ARCH_ARMV5 +QT_BEGIN_INCLUDE_HEADER +# include "QtCore/qatomic_armv5.h" +QT_END_INCLUDE_HEADER +#endif + +QT_END_HEADER + +#endif // QATOMIC_ARM_H diff --git a/src/corelib/arch/qatomic_armv5.h b/src/corelib/arch/qatomic_armv5.h new file mode 100644 index 0000000000..ac8fe9670e --- /dev/null +++ b/src/corelib/arch/qatomic_armv5.h @@ -0,0 +1,431 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ARMV5_H +#define QATOMIC_ARMV5_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#ifndef QT_NO_ARM_EABI + +// kernel places a restartable cmpxchg implementation at a fixed address +extern "C" typedef int (qt_atomic_eabi_cmpxchg_int_t)(int oldval, int newval, volatile int *ptr); +extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(const void *oldval, const void *newval, volatile void *ptr); +#define qt_atomic_eabi_cmpxchg_int (*reinterpret_cast(0xffff0fc0)) +#define qt_atomic_eabi_cmpxchg_ptr (*reinterpret_cast(0xffff0fc0)) + +#else + +extern Q_CORE_EXPORT char q_atomic_lock; +Q_CORE_EXPORT void qt_atomic_yield(int *); + +#ifdef Q_CC_RVCT + +Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval); + +#else + +inline char q_atomic_swp(volatile char *ptr, char newval) +{ + register char ret; + asm volatile("swpb %0,%2,[%3]" + : "=&r"(ret), "=m" (*ptr) + : "r"(newval), "r"(ptr) + : "cc", "memory"); + return ret; +} + +#endif // Q_CC_RVCT + +#endif // QT_NO_ARM_EABI + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ +#ifndef QT_NO_ARM_EABI + register int originalValue; + register int newValue; + do { + originalValue = _q_value; + newValue = originalValue + 1; + } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); + return newValue != 0; +#else + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + int originalValue = _q_value++; + q_atomic_swp(&q_atomic_lock, 0); + return originalValue != -1; +#endif +} + +inline bool QBasicAtomicInt::deref() +{ +#ifndef QT_NO_ARM_EABI + register int originalValue; + register int newValue; + do { + originalValue = _q_value; + newValue = originalValue - 1; + } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); + return newValue != 0; +#else + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + int originalValue = _q_value--; + q_atomic_swp(&q_atomic_lock, 0); + return originalValue != 1; +#endif +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ +#ifndef QT_NO_ARM_EABI + register int originalValue; + do { + originalValue = _q_value; + if (originalValue != expectedValue) + return false; + } while (qt_atomic_eabi_cmpxchg_int(expectedValue, newValue, &_q_value) != 0); + return true; +#else + bool returnValue = false; + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + if (_q_value == expectedValue) { + _q_value = newValue; + returnValue = true; + } + q_atomic_swp(&q_atomic_lock, 0); + return returnValue; +#endif +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +#ifndef Q_CC_RVCT + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + int originalValue; + asm volatile("swp %0,%2,[%3]" + : "=&r"(originalValue), "=m" (_q_value) + : "r"(newValue), "r"(&_q_value) + : "cc", "memory"); + return originalValue; +} + +#endif + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ +#ifndef QT_NO_ARM_EABI + register int originalValue; + register int newValue; + do { + originalValue = _q_value; + newValue = originalValue + valueToAdd; + } while (qt_atomic_eabi_cmpxchg_int(originalValue, newValue, &_q_value) != 0); + return originalValue; +#else + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + int originalValue = _q_value; + _q_value += valueToAdd; + q_atomic_swp(&q_atomic_lock, 0); + return originalValue; +#endif +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ +#ifndef QT_NO_ARM_EABI + register T *originalValue; + do { + originalValue = _q_value; + if (originalValue != expectedValue) + return false; + } while (qt_atomic_eabi_cmpxchg_ptr(expectedValue, newValue, &_q_value) != 0); + return true; +#else + bool returnValue = false; + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + if (_q_value == expectedValue) { + _q_value = newValue; + returnValue = true; + } + q_atomic_swp(&q_atomic_lock, 0); + return returnValue; +#endif +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +#ifdef Q_CC_RVCT + +template +__asm T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + add r2, pc, #0 + bx r2 + arm + swp r2,r1,[r0] + mov r0, r2 + bx lr + thumb +} + +#else + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + T *originalValue; + asm volatile("swp %0,%2,[%3]" + : "=&r"(originalValue), "=m" (_q_value) + : "r"(newValue), "r"(&_q_value) + : "cc", "memory"); + return originalValue; +} + +#endif // Q_CC_RVCT + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ +#ifndef QT_NO_ARM_EABI + register T *originalValue; + register T *newValue; + do { + originalValue = _q_value; + newValue = originalValue + valueToAdd; + } while (qt_atomic_eabi_cmpxchg_ptr(originalValue, newValue, &_q_value) != 0); + return originalValue; +#else + int count = 0; + while (q_atomic_swp(&q_atomic_lock, ~0) != 0) + qt_atomic_yield(&count); + T *originalValue = (_q_value); + _q_value += valueToAdd; + q_atomic_swp(&q_atomic_lock, 0); + return originalValue; +#endif +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_ARMV5_H diff --git a/src/corelib/arch/qatomic_armv6.h b/src/corelib/arch/qatomic_armv6.h new file mode 100644 index 0000000000..3bd605853f --- /dev/null +++ b/src/corelib/arch/qatomic_armv6.h @@ -0,0 +1,559 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ARMV6_H +#define QATOMIC_ARMV6_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#ifndef Q_CC_RVCT + +#ifndef Q_DATA_MEMORY_BARRIER +# define Q_DATA_MEMORY_BARRIER asm volatile("":::"memory") +#endif +#ifndef Q_COMPILER_MEMORY_BARRIER +# define Q_COMPILER_MEMORY_BARRIER asm volatile("":::"memory") +#endif + +inline bool QBasicAtomicInt::ref() +{ + register int newValue; + register int result; + asm volatile("0:\n" + "ldrex %[newValue], [%[_q_value]]\n" + "add %[newValue], %[newValue], #1\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [newValue] "=&r" (newValue), + [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + register int newValue; + register int result; + asm volatile("0:\n" + "ldrex %[newValue], [%[_q_value]]\n" + "sub %[newValue], %[newValue], #1\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [newValue] "=&r" (newValue), + [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int result; + asm volatile("0:\n" + "ldrex %[result], [%[_q_value]]\n" + "eors %[result], %[result], %[expectedValue]\n" + "strexeq %[result], %[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + return result == 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int originalValue; + register int result; + asm volatile("0:\n" + "ldrex %[originalValue], [%[_q_value]]\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [originalValue] "=&r" (originalValue), + [result] "=&r" (result), + "+m" (_q_value) + : [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int originalValue; + register int newValue; + register int result; + asm volatile("0:\n" + "ldrex %[originalValue], [%[_q_value]]\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + [result] "=&r" (result), + "+m" (_q_value) + : [valueToAdd] "r" (valueToAdd), + [_q_value] "r" (&_q_value) + : "cc"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register T *result; + asm volatile("0:\n" + "ldrex %[result], [%[_q_value]]\n" + "eors %[result], %[result], %[expectedValue]\n" + "strexeq %[result], %[newValue], [%[_q_value]]\n" + "teqeq %[result], #1\n" + "beq 0b\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *originalValue; + register int result; + asm volatile("0:\n" + "ldrex %[originalValue], [%[_q_value]]\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [originalValue] "=&r" (originalValue), + [result] "=&r" (result), + "+m" (_q_value) + : [newValue] "r" (newValue), + [_q_value] "r" (&_q_value) + : "cc"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + register int result; + asm volatile("0:\n" + "ldrex %[originalValue], [%[_q_value]]\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + "strex %[result], %[newValue], [%[_q_value]]\n" + "teq %[result], #0\n" + "bne 0b\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + [result] "=&r" (result), + "+m" (_q_value) + : [valueToAdd] "r" (valueToAdd * sizeof(T)), + [_q_value] "r" (&_q_value) + : "cc"); + return originalValue; +} + +#else +// This is Q_CC_RVCT + +// RVCT inline assembly documentation: +// http://www.keil.com/support/man/docs/armcc/armcc_chdcffdb.htm +// RVCT embedded assembly documentation: +// http://www.keil.com/support/man/docs/armcc/armcc_chddbeib.htm + +#if __TARGET_ARCH_THUMB-0 < 4 +// save our pragma state and switch to ARM mode (unless using Thumb2) +# pragma push +# pragma arm +#endif + +#ifndef Q_DATA_MEMORY_BARRIER +# define Q_DATA_MEMORY_BARRIER __schedule_barrier() +#endif +#ifndef Q_COMPILER_MEMORY_BARRIER +# define Q_COMPILER_MEMORY_BARRIER __schedule_barrier() +#endif + +inline bool QBasicAtomicInt::ref() +{ + register int newValue; + register int result; + retry: + __asm { + ldrex newValue, [&_q_value] + add newValue, newValue, #1 + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return newValue != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + register int newValue; + register int result; + retry: + __asm { + ldrex newValue, [&_q_value] + sub newValue, newValue, #1 + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return newValue != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int result; + retry: + __asm { + ldrex result, [&_q_value] + eors result, result, expectedValue + strexeq result, newValue, [&_q_value] + teqeq result, #1 + beq retry + } + return result == 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int originalValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int originalValue; + register int newValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + add newValue, originalValue, valueToAdd + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register T *result; + retry: + __asm { + ldrex result, [&_q_value] + eors result, result, expectedValue + strexeq result, newValue, [&_q_value] + teqeq result, #1 + beq retry + } + return result == 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *originalValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + register int result; + retry: + __asm { + ldrex originalValue, [&_q_value] + add newValue, originalValue, valueToAdd * sizeof(T) + strex result, newValue, [&_q_value] + teq result, #0 + bne retry + } + return originalValue; +} + +#if __TARGET_ARCH_THUMB-0 < 4 +# pragma pop +#endif + +#endif + +// common code + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + bool returnValue = testAndSetRelaxed(expectedValue, newValue); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + Q_DATA_MEMORY_BARRIER; + return testAndSetRelaxed(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + Q_DATA_MEMORY_BARRIER; + bool returnValue = testAndSetRelaxed(expectedValue, newValue); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + int returnValue = fetchAndStoreRelaxed(newValue); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + Q_DATA_MEMORY_BARRIER; + return fetchAndStoreRelaxed(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + Q_DATA_MEMORY_BARRIER; + int returnValue = fetchAndStoreRelaxed(newValue); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + int returnValue = fetchAndAddRelaxed(valueToAdd); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + Q_DATA_MEMORY_BARRIER; + return fetchAndAddRelaxed(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + Q_DATA_MEMORY_BARRIER; + int returnValue = fetchAndAddRelaxed(valueToAdd); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + bool returnValue = testAndSetRelaxed(expectedValue, newValue); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + Q_DATA_MEMORY_BARRIER; + return testAndSetRelaxed(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + Q_DATA_MEMORY_BARRIER; + bool returnValue = testAndSetAcquire(expectedValue, newValue); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + T *returnValue = fetchAndStoreRelaxed(newValue); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + Q_DATA_MEMORY_BARRIER; + return fetchAndStoreRelaxed(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + Q_DATA_MEMORY_BARRIER; + T *returnValue = fetchAndStoreRelaxed(newValue); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + T *returnValue = fetchAndAddRelaxed(valueToAdd); + Q_DATA_MEMORY_BARRIER; + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + Q_DATA_MEMORY_BARRIER; + return fetchAndAddRelaxed(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + Q_DATA_MEMORY_BARRIER; + T *returnValue = fetchAndAddRelaxed(valueToAdd); + Q_COMPILER_MEMORY_BARRIER; + return returnValue; +} + +#undef Q_DATA_MEMORY_BARRIER +#undef Q_COMPILER_MEMORY_BARRIER + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_ARMV6_H diff --git a/src/corelib/arch/qatomic_armv7.h b/src/corelib/arch/qatomic_armv7.h new file mode 100644 index 0000000000..b35866b32c --- /dev/null +++ b/src/corelib/arch/qatomic_armv7.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_ARMV7_H +#define QATOMIC_ARMV7_H + +QT_BEGIN_HEADER + +// use the DMB instruction when compiling for ARMv7, ... +#ifndef Q_CC_RCVT +# define Q_DATA_MEMORY_BARRIER asm volatile("dmb\n":::"memory") +#else +# define Q_DATA_MEMORY_BARRIER do{__asm { dmb } __schedule_barrier();}while(0) +#endif + +// ... but the implementation is otherwise identical to that for ARMv6 +QT_BEGIN_INCLUDE_HEADER +#include "QtCore/qatomic_armv6.h" +QT_END_INCLUDE_HEADER + +QT_END_HEADER + +#endif // QATOMIC_ARMV7_H diff --git a/src/corelib/arch/qatomic_avr32.h b/src/corelib/arch/qatomic_avr32.h new file mode 100644 index 0000000000..a650d73332 --- /dev/null +++ b/src/corelib/arch/qatomic_avr32.h @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_AVR32_H +#define QATOMIC_AVR32_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +inline bool QBasicAtomicInt::ref() +{ + return __sync_add_and_fetch(&_q_value, 1); +} + +inline bool QBasicAtomicInt::deref() +{ + return __sync_sub_and_fetch(&_q_value, 1); +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return __sync_bool_compare_and_swap(&_q_value, expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return __sync_lock_test_and_set(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return __sync_fetch_and_add(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return __sync_bool_compare_and_swap(&_q_value, expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return __sync_lock_test_and_set(&_q_value, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return __sync_fetch_and_add(&_q_value, valueToAdd * sizeof(T)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_AVR32_H diff --git a/src/corelib/arch/qatomic_bfin.h b/src/corelib/arch/qatomic_bfin.h new file mode 100644 index 0000000000..dd53342dfa --- /dev/null +++ b/src/corelib/arch/qatomic_bfin.h @@ -0,0 +1,343 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_BFIN_H +#define QATOMIC_BFIN_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) + +QT_BEGIN_INCLUDE_NAMESPACE +#include +QT_END_INCLUDE_NAMESPACE + +inline bool QBasicAtomicInt::ref() +{ + int ret; + asm volatile("R0 = 1;\n\t" + "P0 = %3;\n\t" + "CALL (%2);\n\t" + "%0 = R0;" + : "=da" (ret), "=m" (_q_value) + : "a" (ATOMIC_ADD32), "da" (&_q_value), "m" (_q_value) + : "R0", "R1", "P0", "RETS", "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + int ret; + asm volatile("R0 = 1;\n\t" + "P0 = %3;\n\t" + "CALL (%2);\n\t" + "%0 = R0;" + : "=da" (ret), "=m" (_q_value) + : "a" (ATOMIC_SUB32), "da" (&_q_value), "m" (_q_value) + : "R0", "R1", "P0", "RETS", "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + long int readval; + asm volatile ("P0 = %2;\n\t" + "R1 = %3;\n\t" + "R2 = %4;\n\t" + "CALL (%5);\n\t" + "%0 = R0;\n\t" + : "=da" (readval), "=m" (_q_value) + : "da" (&_q_value), + "da" (expectedValue), + "da" (newValue), + "a" (ATOMIC_CAS32), + "m" (_q_value) + : "P0", "R0", "R1", "R2", "RETS", "memory", "cc"); + return readval == expectedValue; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + asm volatile("R1 = %2;\n\t" + "P0 = %4;\n\t" + "CALL (%3);\n\t" + "%0 = R0;" + : "=da" (newValue), "=m" (_q_value) + : "da" (newValue), "a" (ATOMIC_XCHG32), "da" (&_q_value), "m" (_q_value) + : "R0", "R1", "P0", "RETS", "memory"); + return newValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + int ret; + asm volatile("R0 = %[val];\n\t" + "P0 = %[qvalp];\n\t" + "CALL (%[addr]);\n\t" + "%[ret] = R1;" + : [ret] "=da" (ret), "=m" (_q_value) + : [addr] "a" (ATOMIC_ADD32), [qvalp] "da" (&_q_value), "m" (_q_value), [val] "da" (valueToAdd) + : "R0", "R1", "P0", "RETS", "memory"); + return ret; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + T *readval; + asm volatile ("P0 = %2;\n\t" + "R1 = %3;\n\t" + "R2 = %4;\n\t" + "CALL (%5);\n\t" + "%0 = R0;\n\t" + : "=da" (readval), "=m" (_q_value) + : "da" (&_q_value), + "da" (expectedValue), + "da" (newValue), + "a" (ATOMIC_CAS32), + "m" (_q_value) + : "P0", "R0", "R1", "R2", "RETS", "memory", "cc"); + return readval == expectedValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + asm volatile("R1 = %2;\n\t" + "P0 = %4;\n\t" + "CALL (%3);\n\t" + "%0 = R0;" + : "=da" (newValue), "=m" (_q_value) + : "da" (newValue), "a" (ATOMIC_XCHG32), "da" (&_q_value), "m" (_q_value) + : "R0", "R1", "P0", "RETS", "memory"); + return newValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + T* ret; + asm volatile("R0 = %[val];\n\t" + "P0 = %[qvalp];\n\t" + "CALL (%[addr]);\n\t" + "%[ret] = R1;" + : [ret] "=da" (ret), "=m" (_q_value) + : [addr] "a" (ATOMIC_ADD32), [qvalp] "da" (&_q_value), "m" (_q_value), [val] "da" (valueToAdd * sizeof(T)) + : "R0", "R1", "P0", "RETS", "memory"); + return ret; +} + + +#endif // Q_OS_LINUX && Q_CC_GNU + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_BFIN_H diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h new file mode 100644 index 0000000000..7927d8b557 --- /dev/null +++ b/src/corelib/arch/qatomic_bootstrap.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_BOOTSTRAP_H +#define QATOMIC_BOOTSTRAP_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +inline bool QBasicAtomicInt::ref() +{ + return ++_q_value != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return --_q_value != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + if (_q_value == expectedValue) { + _q_value = newValue; + return true; + } + return false; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + int returnValue = _q_value; + _q_value += valueToAdd; + return returnValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + if (_q_value == expectedValue) { + _q_value = newValue; + return true; + } + return false; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_BOOTSTRAP_H diff --git a/src/corelib/arch/qatomic_generic.h b/src/corelib/arch/qatomic_generic.h new file mode 100644 index 0000000000..d9c864798e --- /dev/null +++ b/src/corelib/arch/qatomic_generic.h @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_GENERIC_H +#define QATOMIC_GENERIC_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +Q_CORE_EXPORT bool QBasicAtomicInt_testAndSetOrdered(volatile int *, int, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndAddOrdered(volatile int *, int); + +Q_CORE_EXPORT bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *, void *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *, qptrdiff); + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + return QBasicAtomicInt_fetchAndAddOrdered(&_q_value, 1) != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + return QBasicAtomicInt_fetchAndAddOrdered(&_q_value, -1) != 1; +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetOrdered(&_q_value, expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return QBasicAtomicInt_fetchAndStoreOrdered(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddOrdered(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + union { T * volatile * typed; void * volatile * voidp; } pointer; + pointer.typed = &_q_value; + return QBasicAtomicPointer_testAndSetOrdered(pointer.voidp, expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + union { T * volatile * typed; void * volatile * voidp; } pointer; + union { T *typed; void *voidp; } returnValue; + pointer.typed = &_q_value; + returnValue.voidp = QBasicAtomicPointer_fetchAndStoreOrdered(pointer.voidp, newValue); + return returnValue.typed; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + union { T * volatile *typed; void * volatile *voidp; } pointer; + union { T *typed; void *voidp; } returnValue; + pointer.typed = &_q_value; + returnValue.voidp = QBasicAtomicPointer_fetchAndAddOrdered(pointer.voidp, valueToAdd * sizeof(T)); + return returnValue.typed; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_GENERIC_H diff --git a/src/corelib/arch/qatomic_i386.h b/src/corelib/arch/qatomic_i386.h new file mode 100644 index 0000000000..73095a94f6 --- /dev/null +++ b/src/corelib/arch/qatomic_i386.h @@ -0,0 +1,361 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_I386_H +#define QATOMIC_I386_H + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return true; } + +#if defined(Q_CC_GNU) || defined(Q_CC_INTEL) + +inline bool QBasicAtomicInt::ref() +{ + unsigned char ret; + asm volatile("lock\n" + "incl %0\n" + "setne %1" + : "=m" (_q_value), "=qm" (ret) + : "m" (_q_value) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + unsigned char ret; + asm volatile("lock\n" + "decl %0\n" + "setne %1" + : "=m" (_q_value), "=qm" (ret) + : "m" (_q_value) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchgl %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "r" (newValue), "0" (expectedValue) + : "memory"); + return ret != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + asm volatile("xchgl %0,%1" + : "=r" (newValue), "+m" (_q_value) + : "0" (newValue) + : "memory"); + return newValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + asm volatile("lock\n" + "xaddl %0,%1" + : "=r" (valueToAdd), "+m" (_q_value) + : "0" (valueToAdd) + : "memory"); + return valueToAdd; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchgl %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "r" (newValue), "0" (expectedValue) + : "memory"); + return ret != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + asm volatile("xchgl %0,%1" + : "=r" (newValue), "+m" (_q_value) + : "0" (newValue) + : "memory"); + return newValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + asm volatile("lock\n" + "xaddl %0,%1" + : "=r" (valueToAdd), "+m" (_q_value) + : "0" (valueToAdd * sizeof(T)) + : "memory"); + return reinterpret_cast(valueToAdd); +} + +#else + +extern "C" { + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_increment(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_decrement(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval); + Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval); + Q_CORE_EXPORT int q_atomic_fetch_and_add_int(volatile int *ptr, int value); + Q_CORE_EXPORT void *q_atomic_fetch_and_add_ptr(volatile void *ptr, int value); +} // extern "C" + +inline bool QBasicAtomicInt::ref() +{ + return q_atomic_increment(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return q_atomic_decrement(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_int(&_q_value, expectedValue, newValue) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return q_atomic_set_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return q_atomic_fetch_and_add_int(&_q_value, valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +#endif + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QATOMIC_I386_H diff --git a/src/corelib/arch/qatomic_ia64.h b/src/corelib/arch/qatomic_ia64.h new file mode 100644 index 0000000000..42f30266d2 --- /dev/null +++ b/src/corelib/arch/qatomic_ia64.h @@ -0,0 +1,813 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_IA64_H +#define QATOMIC_IA64_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +inline bool _q_ia64_fetchadd_immediate(register int value) +{ + return value == 1 || value == -1 + || value == 4 || value == -4 + || value == 8 || value == -8 + || value == 16 || value == -16; +} + +#if defined(Q_CC_INTEL) + +// intrinsics provided by the Intel C++ Compiler +#include + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return static_cast(_InterlockedExchange(&_q_value, newValue)); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + __memory_barrier(); + return static_cast(_InterlockedExchange(&_q_value, newValue)); +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int expectedValueCopy = expectedValue; + return (static_cast(_InterlockedCompareExchange(&_q_value, + newValue, + expectedValueCopy)) + == expectedValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + register int expectedValueCopy = expectedValue; + return (static_cast(_InterlockedCompareExchange_acq(reinterpret_cast(&_q_value), + newValue, + expectedValueCopy)) + == expectedValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + register int expectedValueCopy = expectedValue; + return (static_cast(_InterlockedCompareExchange_rel(reinterpret_cast(&_q_value), + newValue, + expectedValueCopy)) + == expectedValue); +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + __memory_barrier(); + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + if (__builtin_constant_p(valueToAdd)) { + if (valueToAdd == 1) + return __fetchadd4_acq((unsigned int *)&_q_value, 1); + if (valueToAdd == -1) + return __fetchadd4_acq((unsigned int *)&_q_value, -1); + } + return _InterlockedExchangeAdd(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + if (__builtin_constant_p(valueToAdd)) { + if (valueToAdd == 1) + return __fetchadd4_rel((unsigned int *)&_q_value, 1); + if (valueToAdd == -1) + return __fetchadd4_rel((unsigned int *)&_q_value, -1); + } + __memory_barrier(); + return _InterlockedExchangeAdd(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + __memory_barrier(); + return fetchAndAddAcquire(valueToAdd); +} + +inline bool QBasicAtomicInt::ref() +{ + return _InterlockedIncrement(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return _InterlockedDecrement(&_q_value) != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return (T *)_InterlockedExchangePointer(reinterpret_cast(&_q_value), newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + __memory_barrier(); + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register T *expectedValueCopy = expectedValue; + return (_InterlockedCompareExchangePointer(reinterpret_cast(&_q_value), + newValue, + expectedValueCopy) + == expectedValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + union { + volatile void *x; + volatile unsigned long *p; + }; + x = &_q_value; + register T *expectedValueCopy = expectedValue; + return (_InterlockedCompareExchange64_acq(p, quintptr(newValue), quintptr(expectedValueCopy)) + == quintptr(expectedValue)); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + union { + volatile void *x; + volatile unsigned long *p; + }; + x = &_q_value; + register T *expectedValueCopy = expectedValue; + return (_InterlockedCompareExchange64_rel(p, quintptr(newValue), quintptr(expectedValueCopy)) + == quintptr(expectedValue)); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + __memory_barrier(); + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return (T *)_InterlockedExchangeAdd64((volatile long *)&_q_value, + valueToAdd * sizeof(T)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + __memory_barrier(); + return (T *)_InterlockedExchangeAdd64((volatile long *)&_q_value, + valueToAdd * sizeof(T)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + __memory_barrier(); + return fetchAndAddAcquire(valueToAdd); +} + +#else // !Q_CC_INTEL + +# if defined(Q_CC_GNU) + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + int ret; + asm volatile("xchg4 %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return ret; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + int ret; + asm volatile("mf\n" + "xchg4 %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return ret; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + int ret; + asm volatile("mov ar.ccv=%2\n" + ";;\n" + "cmpxchg4.acq %0=%1,%3,ar.ccv\n" + : "=r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret == expectedValue; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + int ret; + asm volatile("mov ar.ccv=%2\n" + ";;\n" + "cmpxchg4.rel %0=%1,%3,ar.ccv\n" + : "=r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret == expectedValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + int ret; + +#if (__GNUC__ >= 4) + // We implement a fast fetch-and-add when we can + if (__builtin_constant_p(valueToAdd) && _q_ia64_fetchadd_immediate(valueToAdd)) { + asm volatile("fetchadd4.acq %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "i" (valueToAdd) + : "memory"); + return ret; + } +#endif + + // otherwise, use a loop around test-and-set + ret = _q_value; + asm volatile("0:\n" + " mov r9=%0\n" + " mov ar.ccv=%0\n" + " add %0=%0, %2\n" + " ;;\n" + " cmpxchg4.acq %0=%1,%0,ar.ccv\n" + " ;;\n" + " cmp.ne p6,p0 = %0, r9\n" + "(p6) br.dptk 0b\n" + "1:\n" + : "+r" (ret), "+m" (_q_value) + : "r" (valueToAdd) + : "r9", "p6", "memory"); + return ret; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + int ret; + +#if (__GNUC__ >= 4) + // We implement a fast fetch-and-add when we can + if (__builtin_constant_p(valueToAdd) && _q_ia64_fetchadd_immediate(valueToAdd)) { + asm volatile("fetchadd4.rel %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "i" (valueToAdd) + : "memory"); + return ret; + } +#endif + + // otherwise, use a loop around test-and-set + ret = _q_value; + asm volatile("0:\n" + " mov r9=%0\n" + " mov ar.ccv=%0\n" + " add %0=%0, %2\n" + " ;;\n" + " cmpxchg4.rel %0=%1,%0,ar.ccv\n" + " ;;\n" + " cmp.ne p6,p0 = %0, r9\n" + "(p6) br.dptk 0b\n" + "1:\n" + : "+r" (ret), "+m" (_q_value) + : "r" (valueToAdd) + : "r9", "p6", "memory"); + return ret; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + asm volatile("mf" ::: "memory"); + return fetchAndAddRelease(valueToAdd); +} + +inline bool QBasicAtomicInt::ref() +{ + int ret; + asm volatile("fetchadd4.acq %0=%1,1\n" + : "=r" (ret), "+m" (_q_value) + : + : "memory"); + return ret != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + int ret; + asm volatile("fetchadd4.rel %0=%1,-1\n" + : "=r" (ret), "+m" (_q_value) + : + : "memory"); + return ret != 1; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + T *ret; + asm volatile("xchg8 %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return ret; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + T *ret; + asm volatile("mf\n" + "xchg8 %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "r" (newValue) + : "memory"); + return ret; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + T *ret; + asm volatile("mov ar.ccv=%2\n" + ";;\n" + "cmpxchg8.acq %0=%1,%3,ar.ccv\n" + : "=r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret == expectedValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + T *ret; + asm volatile("mov ar.ccv=%2\n" + ";;\n" + "cmpxchg8.rel %0=%1,%3,ar.ccv\n" + : "=r" (ret), "+m" (_q_value) + : "r" (expectedValue), "r" (newValue) + : "memory"); + return ret == expectedValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + T *ret; + +#if (__GNUC__ >= 4) + // We implement a fast fetch-and-add when we can + if (__builtin_constant_p(valueToAdd) && _q_ia64_fetchadd_immediate(valueToAdd * sizeof(T))) { + asm volatile("fetchadd8.acq %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "i" (valueToAdd * sizeof(T)) + : "memory"); + return ret; + } +#endif + + // otherwise, use a loop around test-and-set + ret = _q_value; + asm volatile("0:\n" + " mov r9=%0\n" + " mov ar.ccv=%0\n" + " add %0=%0, %2\n" + " ;;\n" + " cmpxchg8.acq %0=%1,%0,ar.ccv\n" + " ;;\n" + " cmp.ne p6,p0 = %0, r9\n" + "(p6) br.dptk 0b\n" + "1:\n" + : "+r" (ret), "+m" (_q_value) + : "r" (valueToAdd * sizeof(T)) + : "r9", "p6", "memory"); + return ret; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + T *ret; + +#if (__GNUC__ >= 4) + // We implement a fast fetch-and-add when we can + if (__builtin_constant_p(valueToAdd) && _q_ia64_fetchadd_immediate(valueToAdd * sizeof(T))) { + asm volatile("fetchadd8.rel %0=%1,%2\n" + : "=r" (ret), "+m" (_q_value) + : "i" (valueToAdd * sizeof(T)) + : "memory"); + return ret; + } +#endif + + // otherwise, use a loop around test-and-set + ret = _q_value; + asm volatile("0:\n" + " mov r9=%0\n" + " mov ar.ccv=%0\n" + " add %0=%0, %2\n" + " ;;\n" + " cmpxchg8.rel %0=%1,%0,ar.ccv\n" + " ;;\n" + " cmp.ne p6,p0 = %0, r9\n" + "(p6) br.dptk 0b\n" + "1:\n" + : "+r" (ret), "+m" (_q_value) + : "r" (valueToAdd * sizeof(T)) + : "r9", "p6", "memory"); + return ret; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + asm volatile("mf" ::: "memory"); + return fetchAndAddRelease(valueToAdd); +} + +#elif defined Q_CC_HPACC + +QT_BEGIN_INCLUDE_NAMESPACE +#include +QT_END_INCLUDE_NAMESPACE + +#define FENCE (_Asm_fence)(_UP_CALL_FENCE | _UP_SYS_FENCE | _DOWN_CALL_FENCE | _DOWN_SYS_FENCE) + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return _Asm_xchg((_Asm_sz)_SZ_W, &_q_value, (unsigned)newValue, + (_Asm_ldhint)_LDHINT_NONE, FENCE); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + _Asm_mf(FENCE); + return _Asm_xchg((_Asm_sz)_SZ_W, &_q_value, (unsigned)newValue, + (_Asm_ldhint)_LDHINT_NONE, FENCE); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (unsigned)expectedValue, FENCE); + int ret = _Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, (unsigned)newValue, (_Asm_ldhint)_LDHINT_NONE); + return ret == expectedValue; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (unsigned)expectedValue, FENCE); + int ret = _Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_REL, + &_q_value, newValue, (_Asm_ldhint)_LDHINT_NONE); + return ret == expectedValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + if (valueToAdd == 1) + return _Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, 1, (_Asm_ldhint)_LDHINT_NONE, FENCE); + else if (valueToAdd == -1) + return _Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, -1, (_Asm_ldhint)_LDHINT_NONE, FENCE); + + // implement the test-and-set loop + register int old, ret; + do { + old = _q_value; + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (unsigned)old, FENCE); + ret = _Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, old + valueToAdd, (_Asm_ldhint)_LDHINT_NONE); + } while (ret != old); + return old; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + if (valueToAdd == 1) + return _Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_REL, + &_q_value, 1, (_Asm_ldhint)_LDHINT_NONE, FENCE); + else if (valueToAdd == -1) + return _Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_REL, + &_q_value, -1, (_Asm_ldhint)_LDHINT_NONE, FENCE); + + // implement the test-and-set loop + register int old, ret; + do { + old = _q_value; + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (unsigned)old, FENCE); + ret = _Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_REL, + &_q_value, old + valueToAdd, (_Asm_ldhint)_LDHINT_NONE); + } while (ret != old); + return old; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + _Asm_mf(FENCE); + return fetchAndAddAcquire(valueToAdd); +} + +inline bool QBasicAtomicInt::ref() +{ + return (int)_Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, 1, (_Asm_ldhint)_LDHINT_NONE, FENCE) != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + return (int)_Asm_fetchadd((_Asm_fasz)_FASZ_W, (_Asm_sem)_SEM_REL, + &_q_value, -1, (_Asm_ldhint)_LDHINT_NONE, FENCE) != 1; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ +#ifdef __LP64__ + return (T *)_Asm_xchg((_Asm_sz)_SZ_D, &_q_value, (quint64)newValue, + (_Asm_ldhint)_LDHINT_NONE, FENCE); +#else + return (T *)_Asm_xchg((_Asm_sz)_SZ_W, &_q_value, (quint32)newValue, + (_Asm_ldhint)_LDHINT_NONE, FENCE); +#endif +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + _Asm_mf(FENCE); + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ +#ifdef __LP64__ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint64)expectedValue, FENCE); + T *ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_D, (_Asm_sem)_SEM_ACQ, + &_q_value, (quint64)newValue, (_Asm_ldhint)_LDHINT_NONE); +#else + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint32)expectedValue, FENCE); + T *ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, (quint32)newValue, (_Asm_ldhint)_LDHINT_NONE); +#endif + return ret == expectedValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ +#ifdef __LP64__ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint64)expectedValue, FENCE); + T *ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_D, (_Asm_sem)_SEM_REL, + &_q_value, (quint64)newValue, (_Asm_ldhint)_LDHINT_NONE); +#else + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint32)expectedValue, FENCE); + T *ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_REL, + &_q_value, (quint32)newValue, (_Asm_ldhint)_LDHINT_NONE); +#endif + return ret == expectedValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + // implement the test-and-set loop + register T *old, *ret; + do { + old = _q_value; +#ifdef __LP64__ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint64)old, FENCE); + ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_D, (_Asm_sem)_SEM_ACQ, + &_q_value, (quint64)(old + valueToAdd), + (_Asm_ldhint)_LDHINT_NONE); +#else + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint32)old, FENCE); + ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_ACQ, + &_q_value, (quint32)(old + valueToAdd), + (_Asm_ldhint)_LDHINT_NONE); +#endif + } while (old != ret); + return old; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + // implement the test-and-set loop + register T *old, *ret; + do { + old = _q_value; +#ifdef __LP64__ + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint64)old, FENCE); + ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_D, (_Asm_sem)_SEM_REL, + &_q_value, (quint64)(old + valueToAdd), + (_Asm_ldhint)_LDHINT_NONE); +#else + _Asm_mov_to_ar((_Asm_app_reg)_AREG_CCV, (quint32)old, FENCE); + ret = (T *)_Asm_cmpxchg((_Asm_sz)_SZ_W, (_Asm_sem)_SEM_REL, + &_q_value, (quint32)(old + valueToAdd), + (_Asm_ldhint)_LDHINT_NONE); +#endif + } while (old != ret); + return old; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + _Asm_mf(FENCE); + return fetchAndAddAcquire(valueToAdd); +} + +#else + +extern "C" { + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); +} // extern "C" + +#endif + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +#endif // Q_CC_INTEL + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreRelease(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreRelaxed(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_IA64_H diff --git a/src/corelib/arch/qatomic_integrity.h b/src/corelib/arch/qatomic_integrity.h new file mode 100644 index 0000000000..6563903a25 --- /dev/null +++ b/src/corelib/arch/qatomic_integrity.h @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_INTEGRITY_H +#define QATOMIC_INTEGRITY_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define qt_i2addr(a) reinterpret_cast
(const_cast(a)) +#define qt_p2addr(a) reinterpret_cast
(const_cast(a)) +#define qt_addr(a) reinterpret_cast
(a) + + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return true; } + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + int oldval; + AtomicModify(qt_i2addr(&_q_value), qt_i2addr(&oldval), 0, 1); + return _q_value != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + int oldval; + AtomicModify(qt_i2addr(&_q_value), qt_i2addr(&oldval), 0, -1U); + return _q_value != 0; +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return TestAndSet(qt_i2addr(&_q_value), expectedValue, newValue) == Success; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + int old_val; + do { + old_val = _q_value; + } while (TestAndSet(qt_i2addr(&_q_value), old_val, newValue) != Success); + return old_val; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + int old_val; + do { + old_val = _q_value; + } while (TestAndSet(qt_i2addr(&_q_value), old_val, old_val + valueToAdd) != Success); + return old_val; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return TestAndSet((Address*)&_q_value, qt_addr(expectedValue), qt_addr(newValue)) == Success; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + Address old_val; + do { + old_val = *reinterpret_cast
(const_cast(newValue)); + } while (TestAndSet(reinterpret_cast
(const_cast(&_q_value)), old_val, qt_addr(newValue)) != Success); + return reinterpret_cast(old_val); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + AtomicModify(qt_p2addr(&_q_value), qt_addr(_q_value), qt_addr(_q_value) + valueToAdd * sizeof(T)); + return _q_value; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_INTEGRITY_H + diff --git a/src/corelib/arch/qatomic_macosx.h b/src/corelib/arch/qatomic_macosx.h new file mode 100644 index 0000000000..be4501f4d2 --- /dev/null +++ b/src/corelib/arch/qatomic_macosx.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_MACOSX_H +#define QATOMIC_MACOSX_H + +QT_BEGIN_HEADER + +#if defined(__x86_64__) +# include +#elif defined(__i386__) +# include +#else // !__x86_64 && !__i386__ +# include +#endif // !__x86_64__ && !__i386__ + +QT_END_HEADER + +#endif // QATOMIC_MACOSX_H diff --git a/src/corelib/arch/qatomic_mips.h b/src/corelib/arch/qatomic_mips.h new file mode 100644 index 0000000000..6f2607c524 --- /dev/null +++ b/src/corelib/arch/qatomic_mips.h @@ -0,0 +1,892 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_MIPS_H +#define QATOMIC_MIPS_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#if defined(Q_CC_GNU) && !defined(Q_OS_IRIX) + +#if _MIPS_SIM == _ABIO32 +#define SET_MIPS2 ".set mips2\n\t" +#else +#define SET_MIPS2 +#endif + +inline bool QBasicAtomicInt::ref() +{ + register int originalValue; + register int newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "addiu %[newValue], %[originalValue], %[one]\n" + "sc %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [one] "i" (1) + : "cc", "memory"); + return originalValue != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + register int originalValue; + register int newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "addiu %[newValue], %[originalValue], %[minusOne]\n" + "sc %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [minusOne] "i" (-1) + : "cc", "memory"); + return originalValue != 1; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int result; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + register int result; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "sync\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + register int result; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + "ll %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int originalValue; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + register int originalValue; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "sync\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + register int originalValue; + register int tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + "sc %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + "sc %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + "sc %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + "sync\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + "ll %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + "sc %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +#if defined(__LP64__) +# define LLP "lld" +# define SCP "scd" +#else +# define LLP "ll" +# define SCP "sc" +#endif + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register T *result; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + register T *result; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "sync\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + register T *result; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + LLP" %[result], %[_q_value]\n" + "xor %[result], %[result], %[expectedValue]\n" + "bnez %[result], 0f\n" + "nop\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "0:\n" + ".set pop\n" + : [result] "=&r" (result), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *originalValue; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + register T *originalValue; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + "sync\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + register T *originalValue; + register T *tempValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "move %[tempValue], %[newValue]\n" + SCP" %[tempValue], %[_q_value]\n" + "beqz %[tempValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [tempValue] "=&r" (tempValue), + [_q_value] "+m" (_q_value) + : [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + SCP" %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile(".set push\n" + SET_MIPS2 + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + SCP" %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + "sync\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile(".set push\n" + SET_MIPS2 + "sync\n" + "0:\n" + LLP" %[originalValue], %[_q_value]\n" + "addu %[newValue], %[originalValue], %[valueToAdd]\n" + SCP" %[newValue], %[_q_value]\n" + "beqz %[newValue], 0b\n" + "nop\n" + ".set pop\n" + : [originalValue] "=&r" (originalValue), + [_q_value] "+m" (_q_value), + [newValue] "=&r" (newValue) + : [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +#else // !Q_CC_GNU + +extern "C" { + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_acquire_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_release_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_test_and_set_acquire_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_test_and_set_release_ptr(volatile void *ptr, void *expected, void *newval); +} // extern "C" + +inline bool QBasicAtomicInt::ref() +{ + register int expected; + for (;;) { + expected = _q_value; + if (q_atomic_test_and_set_int(&_q_value, expected, expected + 1)) + break; + } + return expected != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + register int expected; + for (;;) { + expected = _q_value; + if (q_atomic_test_and_set_int(&_q_value, expected, expected - 1)) + break; + } + return expected != 1; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_release_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetRelaxed(returnValue, newValue)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetAcquire(returnValue, newValue)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetRelease(returnValue, newValue)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetOrdered(returnValue, newValue)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetRelaxed(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetAcquire(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetRelease(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + int returnValue; + for (;;) { + returnValue = _q_value; + if (testAndSetOrdered(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_release_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetRelaxed(returnValue, newValue)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetAcquire(returnValue, newValue)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetRelease(returnValue, newValue)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetOrdered(returnValue, newValue)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetRelaxed(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE +T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetAcquire(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetRelease(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + T *returnValue; + for (;;) { + returnValue = (_q_value); + if (testAndSetOrdered(returnValue, returnValue + valueToAdd)) + break; + } + return returnValue; +} + +#endif // Q_CC_GNU + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_MIPS_H diff --git a/src/corelib/arch/qatomic_parisc.h b/src/corelib/arch/qatomic_parisc.h new file mode 100644 index 0000000000..eeff9266ee --- /dev/null +++ b/src/corelib/arch/qatomic_parisc.h @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_PARISC_H +#define QATOMIC_PARISC_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +extern "C" { + Q_CORE_EXPORT void q_atomic_lock(int *lock); + Q_CORE_EXPORT void q_atomic_unlock(int *lock); +} + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + q_atomic_lock(_q_lock); + bool ret = (++_q_value != 0); + q_atomic_unlock(_q_lock); + return ret; +} + +inline bool QBasicAtomicInt::deref() +{ + q_atomic_lock(_q_lock); + bool ret = (--_q_value != 0); + q_atomic_unlock(_q_lock); + return ret; +} + +// Test-and-set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + q_atomic_lock(_q_lock); + if (_q_value == expectedValue) { + _q_value = newValue; + q_atomic_unlock(_q_lock); + return true; + } + q_atomic_unlock(_q_lock); + return false; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch-and-store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + q_atomic_lock(_q_lock); + int returnValue = _q_value; + _q_value = newValue; + q_atomic_unlock(_q_lock); + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch-and-add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + q_atomic_lock(_q_lock); + int originalValue = _q_value; + _q_value += valueToAdd; + q_atomic_unlock(_q_lock); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + q_atomic_lock(_q_lock); + if (_q_value == expectedValue) { + _q_value = newValue; + q_atomic_unlock(_q_lock); + return true; + } + q_atomic_unlock(_q_lock); + return false; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + q_atomic_lock(_q_lock); + T *returnValue = (_q_value); + _q_value = newValue; + q_atomic_unlock(_q_lock); + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + q_atomic_lock(_q_lock); + T *returnValue = (_q_value); + _q_value += valueToAdd; + q_atomic_unlock(_q_lock); + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_PARISC_H diff --git a/src/corelib/arch/qatomic_powerpc.h b/src/corelib/arch/qatomic_powerpc.h new file mode 100644 index 0000000000..e261ff7192 --- /dev/null +++ b/src/corelib/arch/qatomic_powerpc.h @@ -0,0 +1,648 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_POWERPC_H +#define QATOMIC_POWERPC_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#if defined(Q_CC_GNU) + +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) \ + || (!defined(__64BIT__) && !defined(__powerpc64__) && !defined(__ppc64__)) +# define _Q_VALUE "0, %[_q_value]" +# define _Q_VALUE_MEMORY_OPERAND "+m" (_q_value) +# define _Q_VALUE_REGISTER_OPERAND [_q_value] "r" (&_q_value), +#else +// On 64-bit with gcc >= 4.2 +# define _Q_VALUE "%y[_q_value]" +# define _Q_VALUE_MEMORY_OPERAND [_q_value] "+Z" (_q_value) +# define _Q_VALUE_REGISTER_OPERAND +#endif + +inline bool QBasicAtomicInt::ref() +{ + register int originalValue; + register int newValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "addi %[newValue], %[originalValue], %[one]\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&b" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [one] "i" (1) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + register int originalValue; + register int newValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "addi %[newValue], %[originalValue], %[minusOne]\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&b" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [minusOne] "i" (-1) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int result; + asm volatile("lwarx %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+12\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + register int result; + asm volatile("lwarx %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+16\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + "isync\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + register int result; + asm volatile("eieio\n" + "lwarx %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+12\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int originalValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + register int originalValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + "isync\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + register int originalValue; + asm volatile("eieio\n" + "lwarx %[originalValue]," _Q_VALUE "\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile("lwarx %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + "isync\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + register int originalValue; + register int newValue; + asm volatile("eieio\n" + "lwarx %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + "stwcx. %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd) + : "cc", "memory"); + return originalValue; +} + +#if defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) +# define LPARX "ldarx" +# define STPCX "stdcx." +#else +# define LPARX "lwarx" +# define STPCX "stwcx." +#endif + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register void *result; + asm volatile(LPARX" %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+12\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + register void *result; + asm volatile(LPARX" %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+16\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + "isync\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + register void *result; + asm volatile("eieio\n" + LPARX" %[result]," _Q_VALUE "\n" + "xor. %[result], %[result], %[expectedValue]\n" + "bne $+12\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-16\n" + : [result] "=&r" (result), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *originalValue; + asm volatile(LPARX" %[originalValue]," _Q_VALUE "\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + register T *originalValue; + asm volatile(LPARX" %[originalValue]," _Q_VALUE "\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + "isync\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + register T *originalValue; + asm volatile("eieio\n" + LPARX" %[originalValue]," _Q_VALUE "\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-8\n" + : [originalValue] "=&r" (originalValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [newValue] "r" (newValue) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile(LPARX" %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile(LPARX" %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + "isync\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + register T *originalValue; + register T *newValue; + asm volatile("eieio\n" + LPARX" %[originalValue]," _Q_VALUE "\n" + "add %[newValue], %[originalValue], %[valueToAdd]\n" + STPCX" %[newValue]," _Q_VALUE "\n" + "bne- $-12\n" + : [originalValue] "=&r" (originalValue), + [newValue] "=&r" (newValue), + _Q_VALUE_MEMORY_OPERAND + : _Q_VALUE_REGISTER_OPERAND + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "cc", "memory"); + return originalValue; +} + +#undef LPARX +#undef STPCX +#undef _Q_VALUE +#undef _Q_VALUE_MEMORY_OPERAND +#undef _Q_VALUE_REGISTER_OPERAND + +#else + +extern "C" { + int q_atomic_test_and_set_int(volatile int *ptr, int expectedValue, int newValue); + int q_atomic_test_and_set_acquire_int(volatile int *ptr, int expectedValue, int newValue); + int q_atomic_test_and_set_release_int(volatile int *ptr, int expectedValue, int newValue); + int q_atomic_test_and_set_ptr(volatile void *ptr, void *expectedValue, void *newValue); + int q_atomic_test_and_set_acquire_ptr(volatile void *ptr, void *expectedValue, void *newValue); + int q_atomic_test_and_set_release_ptr(volatile void *ptr, void *expectedValue, void *newValue); + int q_atomic_increment(volatile int *); + int q_atomic_decrement(volatile int *); + int q_atomic_set_int(volatile int *, int); + int q_atomic_fetch_and_store_acquire_int(volatile int *ptr, int newValue); + int q_atomic_fetch_and_store_release_int(volatile int *ptr, int newValue); + void *q_atomic_set_ptr(volatile void *, void *); + int q_atomic_fetch_and_store_acquire_ptr(volatile void *ptr, void *newValue); + int q_atomic_fetch_and_store_release_ptr(volatile void *ptr, void *newValue); + int q_atomic_fetch_and_add_int(volatile int *ptr, int valueToAdd); + int q_atomic_fetch_and_add_acquire_int(volatile int *ptr, int valueToAdd); + int q_atomic_fetch_and_add_release_int(volatile int *ptr, int valueToAdd); + void *q_atomic_fetch_and_add_ptr(volatile void *ptr, qptrdiff valueToAdd); + void *q_atomic_fetch_and_add_acquire_ptr(volatile void *ptr, qptrdiff valueToAdd); + void *q_atomic_fetch_and_add_release_ptr(volatile void *ptr, qptrdiff valueToAdd); +} // extern "C" + + +inline bool QBasicAtomicInt::ref() +{ + return q_atomic_increment(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return q_atomic_decrement(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_release_int(&_q_value, expectedValue, newValue) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return q_atomic_set_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return q_atomic_fetch_and_store_acquire_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return q_atomic_fetch_and_store_release_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return q_atomic_fetch_and_add_int(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return q_atomic_fetch_and_add_acquire_int(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return q_atomic_fetch_and_add_release_int(&_q_value, valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_release_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_acquire_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_release_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_ptr(&_q_value, valueToAdd * sizeof(T))); +} +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_acquire_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_release_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +#endif + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_POWERPC_H diff --git a/src/corelib/arch/qatomic_s390.h b/src/corelib/arch/qatomic_s390.h new file mode 100644 index 0000000000..552ebe43fe --- /dev/null +++ b/src/corelib/arch/qatomic_s390.h @@ -0,0 +1,426 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_S390_H +#define QATOMIC_S390_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +#ifdef __GNUC__ +#define __GNU_EXTENSION __extension__ +#else +#define __GNU_EXTENSION +#endif + +#define __CS_LOOP(ptr, op_val, op_string, pre, post) __GNU_EXTENSION ({ \ + volatile int old_val, new_val; \ + __asm__ __volatile__(pre \ + " l %0,0(%3)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%4\n" \ + " cs %0,%1,0(%3)\n" \ + " jl 0b\n" \ + post \ + : "=&d" (old_val), "=&d" (new_val), \ + "=m" (*ptr) \ + : "a" (ptr), "d" (op_val), \ + "m" (*ptr) \ + : "cc", "memory" ); \ + new_val; \ +}) + +#define __CS_OLD_LOOP(ptr, op_val, op_string, pre, post ) __GNU_EXTENSION ({ \ + volatile int old_val, new_val; \ + __asm__ __volatile__(pre \ + " l %0,0(%3)\n" \ + "0: lr %1,%0\n" \ + op_string " %1,%4\n" \ + " cs %0,%1,0(%3)\n" \ + " jl 0b\n" \ + post \ + : "=&d" (old_val), "=&d" (new_val), \ + "=m" (*ptr) \ + : "a" (ptr), "d" (op_val), \ + "m" (*ptr) \ + : "cc", "memory" ); \ + old_val; \ +}) + +#ifdef __s390x__ +#define __CSG_OLD_LOOP(ptr, op_val, op_string, pre, post) __GNU_EXTENSION ({ \ + long old_val, new_val; \ + __asm__ __volatile__(pre \ + " lg %0,0(%3)\n" \ + "0: lgr %1,%0\n" \ + op_string " %1,%4\n" \ + " csg %0,%1,0(%3)\n" \ + " jl 0b\n" \ + post \ + : "=&d" (old_val), "=&d" (new_val), \ + "=m" (*ptr) \ + : "a" (ptr), "d" (op_val), \ + "m" (*ptr) \ + : "cc", "memory" ); \ + old_val; \ +}) +#endif + +inline bool QBasicAtomicInt::ref() +{ + return __CS_LOOP(&_q_value, 1, "ar", "", "") != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return __CS_LOOP(&_q_value, 1, "sr", "", "") != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + int retval; + __asm__ __volatile__( + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); + return retval == 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + int retval; + __asm__ __volatile__( + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:\n" + " bcr 15,0\n" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); + return retval == 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + int retval; + __asm__ __volatile__( + " bcr 15,0\n" + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); + return retval == 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return __CS_OLD_LOOP(&_q_value, newValue, "lr", "", ""); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return __CS_OLD_LOOP(&_q_value, newValue, "lr", "", "bcr 15,0\n"); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return __CS_OLD_LOOP(&_q_value, newValue, "lr", "bcr 15,0\n", ""); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return __CS_OLD_LOOP(&_q_value, valueToAdd, "ar", "", "bcr 15,0\n"); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + int retval; + +#ifndef __s390x__ + __asm__ __volatile__( + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#else + __asm__ __volatile__( + " lgr %0,%3\n" + " csg %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#endif + + return retval == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + int retval; + +#ifndef __s390x__ + __asm__ __volatile__( + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:\n" + " bcr 15,0\n" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#else + __asm__ __volatile__( + " lgr %0,%3\n" + " csg %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:\n" + " bcr 15,0\n" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#endif + + return retval == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + int retval; + +#ifndef __s390x__ + __asm__ __volatile__( + " bcr 15,0\n" + " lr %0,%3\n" + " cs %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#else + __asm__ __volatile__( + " bcr 15,0\n" + " lgr %0,%3\n" + " csg %0,%4,0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + "0:" + : "=&d" (retval), "=m" (_q_value) + : "a" (&_q_value), "d" (expectedValue) , "d" (newValue), + "m" (_q_value) : "cc", "memory" ); +#endif + + return retval == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T* QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ +#ifndef __s390x__ + return (T*)__CS_OLD_LOOP(&_q_value, (int)newValue, "lr", "", ""); +#else + return (T*)__CSG_OLD_LOOP(&_q_value, (long)newValue, "lgr", "", ""); +#endif +} + +template +Q_INLINE_TEMPLATE T* QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ +#ifndef __s390x__ + return (T*)__CS_OLD_LOOP(&_q_value, (int)newValue, "lr", "", "bcr 15,0 \n"); +#else + return (T*)__CSG_OLD_LOOP(&_q_value, (long)newValue, "lgr", "", "bcr 15,0 \n"); +#endif +} + +template +Q_INLINE_TEMPLATE T* QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ +#ifndef __s390x__ + return (T*)__CS_OLD_LOOP(&_q_value, (int)newValue, "lr", "bcr 15,0 \n", ""); +#else + return (T*)__CSG_OLD_LOOP(&_q_value, (long)newValue, "lgr", "bcr 15,0\n", ""); +#endif +} + +template +Q_INLINE_TEMPLATE T* QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +#undef __GNU_EXTENSION + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_S390_H diff --git a/src/corelib/arch/qatomic_sh.h b/src/corelib/arch/qatomic_sh.h new file mode 100644 index 0000000000..0150ca4443 --- /dev/null +++ b/src/corelib/arch/qatomic_sh.h @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_SH_H +#define QATOMIC_SH_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +extern Q_CORE_EXPORT volatile char qt_atomic_lock; +Q_CORE_EXPORT void qt_atomic_yield(int *count); + +inline int qt_atomic_tasb(volatile char *ptr) +{ + register int ret; + asm volatile("tas.b @%2\n" + "movt %0" + : "=&r"(ret), "=m"(*ptr) + : "r"(ptr) + : "cc", "memory"); + return ret; +} + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + int originalValue = _q_value++; + qt_atomic_lock = 0; + return originalValue != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + int originalValue = _q_value--; + qt_atomic_lock = 0; + return originalValue != 1; +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + bool returnValue = false; + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + if (_q_value == expectedValue) { + _q_value = newValue; + returnValue = true; + } + qt_atomic_lock = 0; + return returnValue; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + int originalValue = _q_value; + _q_value = newValue; + qt_atomic_lock = 0; + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + int originalValue = _q_value; + _q_value += valueToAdd; + qt_atomic_lock = 0; + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + bool returnValue = false; + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + if (_q_value == expectedValue) { + _q_value = newValue; + returnValue = true; + } + qt_atomic_lock = 0; + return returnValue; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + T *originalValue = _q_value; + _q_value = newValue; + qt_atomic_lock = 0; + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + int count = 0; + while (qt_atomic_tasb(&qt_atomic_lock) == 0) + qt_atomic_yield(&count); + T *originalValue = (_q_value); + _q_value += valueToAdd; + qt_atomic_lock = 0; + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_SH_H diff --git a/src/corelib/arch/qatomic_sh4a.h b/src/corelib/arch/qatomic_sh4a.h new file mode 100644 index 0000000000..88fd4d451d --- /dev/null +++ b/src/corelib/arch/qatomic_sh4a.h @@ -0,0 +1,537 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_SH4A_H +#define QATOMIC_SH4A_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +QT_END_NAMESPACE + +QT_END_HEADER + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +QT_BEGIN_NAMESPACE + +#if !defined(Q_CC_GNU) +# error "SH-4A support has not been added for this compiler" +#else + +inline bool QBasicAtomicInt::ref() +{ + register int newValue asm("r0"); + asm volatile("0:\n" + "movli.l @%[_q_value], %[newValue]\n" + "add #1,%[newValue]\n" + "movco.l %[newValue], @%[_q_value]\n" + "bf 0b\n" + : [newValue] "=&r" (newValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + register int newValue asm("r0"); + asm volatile("0:\n" + "movli.l @%[_q_value], %[newValue]\n" + "add #-1,%[newValue]\n" + "movco.l %[newValue], @%[_q_value]\n" + "bf 0b\n" + : [newValue] "=&r" (newValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value) + : "cc", "memory"); + return newValue != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + register int result; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + register int result; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + register int result; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + register int originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + register int originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + register int originalValue; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + register int originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + register int originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + register int originalValue; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd) + : "r0", "cc", "memory"); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + register T *result; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + register T *result; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + register T *result; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "xor %[expectedValue], r0\n" + "cmp/eq #0, r0\n" + "bf/s 0f\n" + "mov r0, %[result]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "0:\n" + : [result] "=&r" (result), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [expectedValue] "r" (expectedValue), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return result == 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return testAndSetAcquire(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + register T *originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + register T *originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + register T *originalValue; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "mov %[newValue], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [newValue] "r" (newValue) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return fetchAndStoreAcquire(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + register T *originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + register T *originalValue; + asm volatile("0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + "synco\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + register T *originalValue; + asm volatile("synco\n" + "0:\n" + "movli.l @%[_q_value], r0\n" + "mov r0, %[originalValue]\n" + "add %[valueToAdd], r0\n" + "movco.l r0, @%[_q_value]\n" + "bf 0b\n" + : [originalValue] "=&r" (originalValue), + "+m" (_q_value) + : [_q_value] "r" (&_q_value), + [valueToAdd] "r" (valueToAdd * sizeof(T)) + : "r0", "cc", "memory"); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return fetchAndAddAcquire(valueToAdd); +} + +#endif // Q_CC_GNU + +#endif // QATOMIC_SH4A_H diff --git a/src/corelib/arch/qatomic_sparc.h b/src/corelib/arch/qatomic_sparc.h new file mode 100644 index 0000000000..a89a5f3fe5 --- /dev/null +++ b/src/corelib/arch/qatomic_sparc.h @@ -0,0 +1,525 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_SPARC_H +#define QATOMIC_SPARC_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#if defined(_LP64) + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +extern "C" { + Q_CORE_EXPORT int q_atomic_increment(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_decrement(volatile int *ptr); + + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_acquire_int(volatile int *ptr, + int expected, + int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_release_int(volatile int *ptr, + int expected, + int newval); + + Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval); + Q_CORE_EXPORT int q_atomic_fetch_and_store_acquire_int(volatile int *ptr, int newval); + Q_CORE_EXPORT int q_atomic_fetch_and_store_release_int(volatile int *ptr, int newval); + + Q_CORE_EXPORT int q_atomic_fetch_and_add_int(volatile int *ptr, int value); + Q_CORE_EXPORT int q_atomic_fetch_and_add_acquire_int(volatile int *ptr, int value); + Q_CORE_EXPORT int q_atomic_fetch_and_add_release_int(volatile int *ptr, int value); + + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_test_and_set_acquire_ptr(volatile void *ptr, + void *expected, + void *newval); + Q_CORE_EXPORT int q_atomic_test_and_set_release_ptr(volatile void *ptr, + void *expected, + void *newval); + + Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval); + Q_CORE_EXPORT void *q_atomic_fetch_and_store_acquire_ptr(volatile void *ptr, void *newval); + Q_CORE_EXPORT void *q_atomic_fetch_and_store_release_ptr(volatile void *ptr, void *newval); + + Q_CORE_EXPORT void *q_atomic_fetch_and_add_ptr(volatile void *ptr, int value); + Q_CORE_EXPORT void *q_atomic_fetch_and_add_acquire_ptr(volatile void *ptr, int value); + Q_CORE_EXPORT void *q_atomic_fetch_and_add_release_ptr(volatile void *ptr, int value); +} + +inline bool QBasicAtomicInt::ref() +{ + return fetchAndAddRelaxed(1) != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + return fetchAndAddRelaxed(-1) != 1; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_release_int(&_q_value, expectedValue, newValue) != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return q_atomic_test_and_set_acquire_int(&_q_value, expectedValue, newValue) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return q_atomic_set_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return q_atomic_fetch_and_store_acquire_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return q_atomic_fetch_and_store_release_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return q_atomic_fetch_and_store_acquire_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int newValue) +{ + return q_atomic_fetch_and_add_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int newValue) +{ + return q_atomic_fetch_and_add_acquire_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int newValue) +{ + return q_atomic_fetch_and_add_release_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int newValue) +{ + return q_atomic_fetch_and_add_acquire_int(&_q_value, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_release_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_acquire_ptr(&_q_value, expectedValue, newValue) != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_acquire_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_release_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return reinterpret_cast(q_atomic_fetch_and_store_acquire_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE +T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_acquire_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_release_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_acquire_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +#else + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +extern "C" { + Q_CORE_EXPORT int q_atomic_lock_int(volatile int *addr); + Q_CORE_EXPORT int q_atomic_lock_ptr(volatile void *addr); + Q_CORE_EXPORT void q_atomic_unlock(volatile void *addr, int value); + Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval); + Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval); +} // extern "C" + +inline bool QBasicAtomicInt::ref() +{ + const int val = q_atomic_lock_int(&_q_value); + q_atomic_unlock(&_q_value, val + 1); + return val != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + const int val = q_atomic_lock_int(&_q_value); + q_atomic_unlock(&_q_value, val - 1); + return val != 1; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + int val = q_atomic_lock_int(&_q_value); + if (val == expectedValue) { + q_atomic_unlock(&_q_value, newValue); + return true; + } + q_atomic_unlock(&_q_value, val); + return false; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return q_atomic_set_int(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + const int originalValue = q_atomic_lock_int(&_q_value); + q_atomic_unlock(&_q_value, originalValue + valueToAdd); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + T *val = reinterpret_cast(q_atomic_lock_ptr(&_q_value)); + if (val == expectedValue) { + q_atomic_unlock(&_q_value, reinterpret_cast(newValue)); + return true; + } + q_atomic_unlock(&_q_value, reinterpret_cast(val)); + return false; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + T *originalValue = reinterpret_cast(q_atomic_lock_ptr(&_q_value)); + q_atomic_unlock(&_q_value, int(originalValue + valueToAdd)); + return originalValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +#endif // _LP64 + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_SPARC_H diff --git a/src/corelib/arch/qatomic_symbian.h b/src/corelib/arch/qatomic_symbian.h new file mode 100644 index 0000000000..c4cd301218 --- /dev/null +++ b/src/corelib/arch/qatomic_symbian.h @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_SYMBIAN_H +#define QATOMIC_SYMBIAN_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_SOMETIMES_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_SOMETIMES_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_SOMETIMES_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_SOMETIMES_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_SOMETIMES_NATIVE + +Q_CORE_EXPORT bool QBasicAtomicPointer_isTestAndSetNative(); +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return QBasicAtomicPointer_isTestAndSetNative(); } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_SOMETIMES_NATIVE + +Q_CORE_EXPORT bool QBasicAtomicPointer_isFetchAndStoreNative(); +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return QBasicAtomicPointer_isFetchAndStoreNative(); } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_SOMETIMES_NATIVE + +Q_CORE_EXPORT bool QBasicAtomicPointer_isFetchAndAddNative(); +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return QBasicAtomicPointer_isFetchAndAddNative(); } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +Q_CORE_EXPORT bool QBasicAtomicInt_testAndSetOrdered(volatile int *, int, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndAddOrdered(volatile int *, int); +Q_CORE_EXPORT bool QBasicAtomicInt_testAndSetRelaxed(volatile int *, int, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndStoreRelaxed(volatile int *, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndAddRelaxed(volatile int *, int); +Q_CORE_EXPORT bool QBasicAtomicInt_testAndSetAcquire(volatile int *, int, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndStoreAcquire(volatile int *, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndAddAcquire(volatile int *, int); +Q_CORE_EXPORT bool QBasicAtomicInt_testAndSetRelease(volatile int *, int, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndStoreRelease(volatile int *, int); +Q_CORE_EXPORT int QBasicAtomicInt_fetchAndAddRelease(volatile int *, int); + +Q_CORE_EXPORT bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *, void *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *, qptrdiff); +Q_CORE_EXPORT bool QBasicAtomicPointer_testAndSetRelaxed(void * volatile *, void *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndStoreRelaxed(void * volatile *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndAddRelaxed(void * volatile *, qptrdiff); +Q_CORE_EXPORT bool QBasicAtomicPointer_testAndSetAcquire(void * volatile *, void *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndStoreAcquire(void * volatile *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndAddAcquire(void * volatile *, qptrdiff); +Q_CORE_EXPORT bool QBasicAtomicPointer_testAndSetRelease(void * volatile *, void *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndStoreRelease(void * volatile *, void *); +Q_CORE_EXPORT void *QBasicAtomicPointer_fetchAndAddRelease(void * volatile *, qptrdiff); + +// Reference counting + +//LockedInc and LockedDec are machine coded for ARMv6 (and future proof) +inline bool QBasicAtomicInt::ref() +{ + int original = User::LockedInc((TInt&)_q_value); + return original != -1; +} + +inline bool QBasicAtomicInt::deref() +{ + int original = User::LockedDec((TInt&)_q_value); + return original != 1; +} + +// Test and set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetOrdered(&_q_value, expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetRelaxed(&_q_value, expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetAcquire(&_q_value, expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetRelease(&_q_value, expectedValue, newValue); +} + +// Fetch and store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return QBasicAtomicInt_fetchAndStoreOrdered(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return QBasicAtomicInt_fetchAndStoreRelaxed(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return QBasicAtomicInt_fetchAndStoreAcquire(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return QBasicAtomicInt_fetchAndStoreRelease(&_q_value, newValue); +} + +// Fetch and add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddOrdered(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddRelaxed(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddAcquire(&_q_value, valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddRelease(&_q_value, valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return QBasicAtomicPointer_testAndSetOrdered(reinterpret_cast(&_q_value), + expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return QBasicAtomicPointer_testAndSetRelaxed(reinterpret_cast(&_q_value), + expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return QBasicAtomicPointer_testAndSetAcquire(reinterpret_cast(&_q_value), + expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return QBasicAtomicPointer_testAndSetRelease(reinterpret_cast(&_q_value), + expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return static_cast(QBasicAtomicPointer_fetchAndStoreOrdered( + reinterpret_cast(&_q_value) + , newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return static_cast(QBasicAtomicPointer_fetchAndStoreRelaxed( + reinterpret_cast(&_q_value) + , newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return static_cast(QBasicAtomicPointer_fetchAndStoreAcquire( + reinterpret_cast(&_q_value) + , newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return static_cast(QBasicAtomicPointer_fetchAndStoreRelease( + reinterpret_cast(&_q_value) + , newValue)); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return static_cast(QBasicAtomicPointer_fetchAndAddOrdered( + reinterpret_cast(&_q_value), + valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return static_cast(QBasicAtomicPointer_fetchAndAddRelaxed( + reinterpret_cast(&_q_value), + valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return static_cast(QBasicAtomicPointer_fetchAndAddAcquire( + reinterpret_cast(&_q_value), + valueToAdd * sizeof(T))); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return static_cast(QBasicAtomicPointer_fetchAndAddRelease( + reinterpret_cast(&_q_value), + valueToAdd * sizeof(T))); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_SYMBIAN_H diff --git a/src/corelib/arch/qatomic_vxworks.h b/src/corelib/arch/qatomic_vxworks.h new file mode 100644 index 0000000000..9386d19ece --- /dev/null +++ b/src/corelib/arch/qatomic_vxworks.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_VXWORKS_H +#define QATOMIC_VXWORKS_H + +QT_BEGIN_HEADER + +#if defined(__ppc) +# include +#else // generic implementation with taskLock() + +#if 0 +// we don't want to include the system header here for two function prototypes, +// because it pulls in a _lot_ of stuff that pollutes the global namespace +# include +# include +#else +extern "C" int taskLock(); +extern "C" int taskUnlock(); +#endif + + + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return false; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return false; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_NOT_NATIVE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return false; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return false; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_NOT_NATIVE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return false; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return false; } + +// Reference counting + +inline bool QBasicAtomicInt::ref() +{ + taskLock(); + bool ret = (++_q_value != 0); + taskUnlock(); + return ret; +} + +inline bool QBasicAtomicInt::deref() +{ + taskLock(); + bool ret = (--_q_value != 0); + taskUnlock(); + return ret; +} + +// Test-and-set for integers + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + taskLock(); + if (_q_value == expectedValue) { + _q_value = newValue; + taskUnlock(); + return true; + } + taskUnlock(); + return false; +} + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch-and-store for integers + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + taskLock(); + int returnValue = _q_value; + _q_value = newValue; + taskUnlock(); + return returnValue; +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch-and-add for integers + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + taskLock(); + int originalValue = _q_value; + _q_value += valueToAdd; + taskUnlock(); + return originalValue; +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +// Test and set for pointers + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + taskLock(); + if (_q_value == expectedValue) { + _q_value = newValue; + taskUnlock(); + return true; + } + taskUnlock(); + return false; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +// Fetch and store for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + taskLock(); + T *returnValue = (_q_value); + _q_value = newValue; + taskUnlock(); + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +// Fetch and add for pointers + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + taskLock(); + T *returnValue = (_q_value); + _q_value += valueToAdd; + taskUnlock(); + return returnValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +#endif // generic implementation with taskLock() + +QT_END_HEADER + +#endif // QATOMIC_VXWORKS_H diff --git a/src/corelib/arch/qatomic_windows.h b/src/corelib/arch/qatomic_windows.h new file mode 100644 index 0000000000..538c00cff1 --- /dev/null +++ b/src/corelib/arch/qatomic_windows.h @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_WINDOWS_H +#define QATOMIC_WINDOWS_H + +#ifndef Q_CC_MSVC + +// Mingw and other GCC platforms get inline assembly + +# ifdef __i386__ +# include "QtCore/qatomic_i386.h" +# else +# include "QtCore/qatomic_x86_64.h" +# endif + +#else // Q_CC_MSVC + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef Q_OS_WINCE + +// use compiler intrinsics for all atomic functions +# define QT_INTERLOCKED_PREFIX _ +# define QT_INTERLOCKED_PROTOTYPE __cdecl +# define QT_INTERLOCKED_DECLARE_PROTOTYPES +# define QT_INTERLOCKED_INTRINSIC + +#else // Q_OS_WINCE + +# if _WIN32_WCE < 0x600 && defined(_X86_) +// For X86 Windows CE, include winbase.h to catch inline functions which +// override the regular definitions inside of coredll.dll. +// Though one could use the original version of Increment/Decrement, others are +// not exported at all. +# include + +// It's safer to remove the volatile and let the compiler add it as needed. +# define QT_INTERLOCKED_NO_VOLATILE + +# else // _WIN32_WCE >= 0x600 || !_X86_ + +# define QT_INTERLOCKED_PROTOTYPE __cdecl +# define QT_INTERLOCKED_DECLARE_PROTOTYPES + +# if _WIN32_WCE >= 0x600 +# if defined(_X86_) +# define QT_INTERLOCKED_PREFIX _ +# define QT_INTERLOCKED_INTRINSIC +# endif +# else +# define QT_INTERLOCKED_NO_VOLATILE +# endif + +# endif // _WIN32_WCE >= 0x600 || !_X86_ + +#endif // Q_OS_WINCE + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Prototype declaration + +#define QT_INTERLOCKED_CONCAT_I(prefix, suffix) \ + prefix ## suffix +#define QT_INTERLOCKED_CONCAT(prefix, suffix) \ + QT_INTERLOCKED_CONCAT_I(prefix, suffix) + +// MSVC intrinsics prefix function names with an underscore. Also, if platform +// SDK headers have been included, the Interlocked names may be defined as +// macros. +// To avoid double underscores, we paste the prefix with Interlocked first and +// then the remainder of the function name. +#define QT_INTERLOCKED_FUNCTION(name) \ + QT_INTERLOCKED_CONCAT( \ + QT_INTERLOCKED_CONCAT(QT_INTERLOCKED_PREFIX, Interlocked), name) + +#ifdef QT_INTERLOCKED_NO_VOLATILE +# define QT_INTERLOCKED_VOLATILE +# define QT_INTERLOCKED_REMOVE_VOLATILE(a) qt_interlocked_remove_volatile(a) +#else +# define QT_INTERLOCKED_VOLATILE volatile +# define QT_INTERLOCKED_REMOVE_VOLATILE(a) a +#endif + +#ifndef QT_INTERLOCKED_PREFIX +#define QT_INTERLOCKED_PREFIX +#endif + +#ifndef QT_INTERLOCKED_PROTOTYPE +#define QT_INTERLOCKED_PROTOTYPE +#endif + +#ifdef QT_INTERLOCKED_DECLARE_PROTOTYPES +#undef QT_INTERLOCKED_DECLARE_PROTOTYPES + +extern "C" { + + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Increment )(long QT_INTERLOCKED_VOLATILE *); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Decrement )(long QT_INTERLOCKED_VOLATILE *); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( CompareExchange )(long QT_INTERLOCKED_VOLATILE *, long, long); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( Exchange )(long QT_INTERLOCKED_VOLATILE *, long); + long QT_INTERLOCKED_PROTOTYPE QT_INTERLOCKED_FUNCTION( ExchangeAdd )(long QT_INTERLOCKED_VOLATILE *, long); + +# if !defined(Q_OS_WINCE) && !defined(__i386__) && !defined(_M_IX86) + void * QT_INTERLOCKED_FUNCTION( CompareExchangePointer )(void * QT_INTERLOCKED_VOLATILE *, void *, void *); + void * QT_INTERLOCKED_FUNCTION( ExchangePointer )(void * QT_INTERLOCKED_VOLATILE *, void *); + __int64 QT_INTERLOCKED_FUNCTION( ExchangeAdd64 )(__int64 QT_INTERLOCKED_VOLATILE *, __int64); +# endif + +} + +#endif // QT_INTERLOCKED_DECLARE_PROTOTYPES + +#undef QT_INTERLOCKED_PROTOTYPE + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef QT_INTERLOCKED_INTRINSIC +#undef QT_INTERLOCKED_INTRINSIC + +# pragma intrinsic (_InterlockedIncrement) +# pragma intrinsic (_InterlockedDecrement) +# pragma intrinsic (_InterlockedExchange) +# pragma intrinsic (_InterlockedCompareExchange) +# pragma intrinsic (_InterlockedExchangeAdd) + +# if !defined(Q_OS_WINCE) && !defined(_M_IX86) +# pragma intrinsic (_InterlockedCompareExchangePointer) +# pragma intrinsic (_InterlockedExchangePointer) +# pragma intrinsic (_InterlockedExchangeAdd64) +# endif + +#endif // QT_INTERLOCKED_INTRINSIC + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interlocked* replacement macros + +#define QT_INTERLOCKED_INCREMENT(value) \ + QT_INTERLOCKED_FUNCTION( Increment )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ) ) + +#define QT_INTERLOCKED_DECREMENT(value) \ + QT_INTERLOCKED_FUNCTION( Decrement )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ) ) + +#define QT_INTERLOCKED_COMPARE_EXCHANGE(value, newValue, expectedValue) \ + QT_INTERLOCKED_FUNCTION( CompareExchange )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue, \ + expectedValue ) + +#define QT_INTERLOCKED_EXCHANGE(value, newValue) \ + QT_INTERLOCKED_FUNCTION( Exchange )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + newValue ) + +#define QT_INTERLOCKED_EXCHANGE_ADD(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION( ExchangeAdd )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ), \ + valueToAdd ) + +#if defined(Q_OS_WINCE) || defined(__i386__) || defined(_M_IX86) + +# define QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(value, newValue, expectedValue) \ + reinterpret_cast( \ + QT_INTERLOCKED_FUNCTION( CompareExchange )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + (long)( newValue ), \ + (long)( expectedValue ) )) + +# define QT_INTERLOCKED_EXCHANGE_POINTER(value, newValue) \ + QT_INTERLOCKED_FUNCTION( Exchange )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + (quintptr)( newValue ) ) + +# define QT_INTERLOCKED_EXCHANGE_ADD_POINTER(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION( ExchangeAdd )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + valueToAdd ) + +#else // !defined(Q_OS_WINCE) && !defined(__i386__) && !defined(_M_IX86) + +# define QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(value, newValue, expectedValue) \ + QT_INTERLOCKED_FUNCTION( CompareExchangePointer )( \ + reinterpret_cast( QT_INTERLOCKED_REMOVE_VOLATILE( value ) ), \ + newValue, \ + expectedValue ) + +# define QT_INTERLOCKED_EXCHANGE_POINTER(value, newValue) \ + QT_INTERLOCKED_FUNCTION( ExchangePointer )( \ + reinterpret_cast( QT_INTERLOCKED_REMOVE_VOLATILE( value ) ), \ + newValue ) + +# define QT_INTERLOCKED_EXCHANGE_ADD_POINTER(value, valueToAdd) \ + QT_INTERLOCKED_FUNCTION( ExchangeAdd64 )( \ + QT_INTERLOCKED_REMOVE_VOLATILE( value ## _integral ), \ + valueToAdd ) + +#endif // !defined(Q_OS_WINCE) && !defined(__i386__) && !defined(_M_IX86) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return true; } + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef QT_INTERLOCKED_NO_VOLATILE +template +Q_INLINE_TEMPLATE T *qt_interlocked_remove_volatile(T volatile *t) +{ + return const_cast(t); +} +#endif // !QT_INTERLOCKED_NO_VOLATILE + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline bool QBasicAtomicInt::ref() +{ + return QT_INTERLOCKED_INCREMENT(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return QT_INTERLOCKED_DECREMENT(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + return QT_INTERLOCKED_COMPARE_EXCHANGE(&_q_value, newValue, expectedValue) + == expectedValue; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + return QT_INTERLOCKED_EXCHANGE(&_q_value, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + return QT_INTERLOCKED_EXCHANGE_ADD(&_q_value, valueToAdd); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&_q_value, newValue, expectedValue) + == expectedValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T* newValue) +{ + return reinterpret_cast( + QT_INTERLOCKED_EXCHANGE_POINTER(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return reinterpret_cast( + QT_INTERLOCKED_EXCHANGE_ADD_POINTER(&_q_value, valueToAdd * sizeof(T))); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Cleanup + +#undef QT_INTERLOCKED_CONCAT_I +#undef QT_INTERLOCKED_CONCAT +#undef QT_INTERLOCKED_FUNCTION +#undef QT_INTERLOCKED_PREFIX + +#undef QT_INTERLOCKED_NO_VOLATILE +#undef QT_INTERLOCKED_VOLATILE +#undef QT_INTERLOCKED_REMOVE_VOLATILE + +#undef QT_INTERLOCKED_INCREMENT +#undef QT_INTERLOCKED_DECREMENT +#undef QT_INTERLOCKED_COMPARE_EXCHANGE +#undef QT_INTERLOCKED_EXCHANGE +#undef QT_INTERLOCKED_EXCHANGE_ADD +#undef QT_INTERLOCKED_COMPARE_EXCHANGE_POINTER +#undef QT_INTERLOCKED_EXCHANGE_POINTER +#undef QT_INTERLOCKED_EXCHANGE_ADD_POINTER + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // Q_CC_MSVC + +#endif // QATOMIC_WINDOWS_H diff --git a/src/corelib/arch/qatomic_windowsce.h b/src/corelib/arch/qatomic_windowsce.h new file mode 100644 index 0000000000..25696f9626 --- /dev/null +++ b/src/corelib/arch/qatomic_windowsce.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WINDOWSCE_QATOMIC_H +#define WINDOWSCE_QATOMIC_H + +#include +QT_BEGIN_HEADER + +#if defined(QT_ARCH_WINDOWSCE) +#include "QtCore/qatomic_windows.h" +#endif + +QT_END_HEADER + +#endif // QATOMIC_ARCH_H + + diff --git a/src/corelib/arch/qatomic_x86_64.h b/src/corelib/arch/qatomic_x86_64.h new file mode 100644 index 0000000000..9303f191ce --- /dev/null +++ b/src/corelib/arch/qatomic_x86_64.h @@ -0,0 +1,363 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_X86_64_H +#define QATOMIC_X86_64_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_REFERENCE_COUNTING_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isReferenceCountingNative() +{ return true; } +inline bool QBasicAtomicInt::isReferenceCountingWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_TEST_AND_SET_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isTestAndSetNative() +{ return true; } +inline bool QBasicAtomicInt::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_STORE_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndStoreNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_INT_FETCH_AND_ADD_IS_WAIT_FREE + +inline bool QBasicAtomicInt::isFetchAndAddNative() +{ return true; } +inline bool QBasicAtomicInt::isFetchAndAddWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_TEST_AND_SET_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isTestAndSetWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_STORE_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndStoreWaitFree() +{ return true; } + +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_ALWAYS_NATIVE +#define Q_ATOMIC_POINTER_FETCH_AND_ADD_IS_WAIT_FREE + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddNative() +{ return true; } +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::isFetchAndAddWaitFree() +{ return true; } + +#if defined(Q_CC_GNU) || defined(Q_CC_INTEL) + +inline bool QBasicAtomicInt::ref() +{ + unsigned char ret; + asm volatile("lock\n" + "incl %0\n" + "setne %1" + : "=m" (_q_value), "=qm" (ret) + : "m" (_q_value) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + unsigned char ret; + asm volatile("lock\n" + "decl %0\n" + "setne %1" + : "=m" (_q_value), "=qm" (ret) + : "m" (_q_value) + : "memory"); + return ret != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expectedValue, int newValue) +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchgl %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "r" (newValue), "0" (expectedValue) + : "memory"); + return ret != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + asm volatile("xchgl %0,%1" + : "=r" (newValue), "+m" (_q_value) + : "0" (newValue) + : "memory"); + return newValue; +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) +{ + asm volatile("lock\n" + "xaddl %0,%1" + : "=r" (valueToAdd), "+m" (_q_value) + : "0" (valueToAdd) + : "memory"); + return valueToAdd; +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + unsigned char ret; + asm volatile("lock\n" + "cmpxchgq %3,%2\n" + "sete %1\n" + : "=a" (newValue), "=qm" (ret), "+m" (_q_value) + : "r" (newValue), "0" (expectedValue) + : "memory"); + return ret != 0; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + asm volatile("xchgq %0,%1" + : "=r" (newValue), "+m" (_q_value) + : "0" (newValue) + : "memory"); + return newValue; +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + asm volatile("lock\n" + "xaddq %0,%1" + : "=r" (valueToAdd), "+m" (_q_value) + : "0" (valueToAdd * sizeof(T)) + : "memory"); + return reinterpret_cast(valueToAdd); +} + +#else // !Q_CC_INTEL && !Q_CC_GNU + +extern "C" { + Q_CORE_EXPORT int q_atomic_test_and_set_int(volatile int *ptr, int expected, int newval); + Q_CORE_EXPORT int q_atomic_test_and_set_ptr(volatile void *ptr, void *expected, void *newval); + Q_CORE_EXPORT int q_atomic_increment(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_decrement(volatile int *ptr); + Q_CORE_EXPORT int q_atomic_set_int(volatile int *ptr, int newval); + Q_CORE_EXPORT void *q_atomic_set_ptr(volatile void *ptr, void *newval); + Q_CORE_EXPORT int q_atomic_fetch_and_add_int(volatile int *ptr, int value); + Q_CORE_EXPORT void *q_atomic_fetch_and_add_ptr(volatile void *ptr, qptrdiff value); +} // extern "C" + +inline bool QBasicAtomicInt::ref() +{ + return q_atomic_increment(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::deref() +{ + return q_atomic_decrement(&_q_value) != 0; +} + +inline bool QBasicAtomicInt::testAndSetOrdered(int expected, int newval) +{ + return q_atomic_test_and_set_int(&_q_value, expected, newval) != 0; +} + +inline int QBasicAtomicInt::fetchAndStoreOrdered(int newval) +{ + return q_atomic_set_int(&_q_value, newval); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int aValue) +{ + return q_atomic_fetch_and_add_int(&_q_value, aValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) +{ + return q_atomic_test_and_set_ptr(&_q_value, expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreOrdered(T *newValue) +{ + return reinterpret_cast(q_atomic_set_ptr(&_q_value, newValue)); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddOrdered(qptrdiff valueToAdd) +{ + return reinterpret_cast(q_atomic_fetch_and_add_ptr(&_q_value, valueToAdd * sizeof(T))); +} + +#endif // Q_CC_GNU || Q_CC_INTEL + +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetAcquire(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreAcquire(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndStoreRelease(int newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelaxed(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetAcquire(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetRelease(T *expectedValue, T *newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelaxed(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreAcquire(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndStoreRelease(T *newValue) +{ + return fetchAndStoreOrdered(newValue); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelaxed(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddAcquire(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +template +Q_INLINE_TEMPLATE T *QBasicAtomicPointer::fetchAndAddRelease(qptrdiff valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QATOMIC_X86_64_H diff --git a/src/corelib/arch/s390/arch.pri b/src/corelib/arch/s390/arch.pri new file mode 100644 index 0000000000..45cc57824b --- /dev/null +++ b/src/corelib/arch/s390/arch.pri @@ -0,0 +1,3 @@ +# +# S390 architecture +# diff --git a/src/corelib/arch/sh/arch.pri b/src/corelib/arch/sh/arch.pri new file mode 100644 index 0000000000..67fbb16c10 --- /dev/null +++ b/src/corelib/arch/sh/arch.pri @@ -0,0 +1,4 @@ +# +# SH (Renesas SuperH) architecture +# +SOURCES += $$QT_ARCH_CPP/qatomic_sh.cpp diff --git a/src/corelib/arch/sh/qatomic_sh.cpp b/src/corelib/arch/sh/qatomic_sh.cpp new file mode 100644 index 0000000000..a27702010a --- /dev/null +++ b/src/corelib/arch/sh/qatomic_sh.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#ifdef _POSIX_PRIORITY_SCHEDULING +# include +#endif +#include + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +Q_CORE_EXPORT volatile char qt_atomic_lock = 0; + +Q_CORE_EXPORT void qt_atomic_yield(int *count) +{ +#ifdef _POSIX_PRIORITY_SCHEDULING + if((*count)++ < 50) { + sched_yield(); + } else +#endif + { + struct timespec tm; + tm.tv_sec = 0; + tm.tv_nsec = 2000001; + nanosleep(&tm, NULL); + *count = 0; + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/arch/sh4a/arch.pri b/src/corelib/arch/sh4a/arch.pri new file mode 100644 index 0000000000..19d5e040a9 --- /dev/null +++ b/src/corelib/arch/sh4a/arch.pri @@ -0,0 +1,3 @@ +# +# SH-4A (Renesas SuperH) architecture +# diff --git a/src/corelib/arch/sparc/arch.pri b/src/corelib/arch/sparc/arch.pri new file mode 100644 index 0000000000..9bb3a888e8 --- /dev/null +++ b/src/corelib/arch/sparc/arch.pri @@ -0,0 +1,10 @@ +# +# SPARC architecture +# +*-64* { + SOURCES += $$QT_ARCH_CPP/qatomic64.s +} +else { + SOURCES += $$QT_ARCH_CPP/qatomic32.s \ + $$QT_ARCH_CPP/qatomic_sparc.cpp +} diff --git a/src/corelib/arch/sparc/qatomic32.s b/src/corelib/arch/sparc/qatomic32.s new file mode 100644 index 0000000000..a242add4bc --- /dev/null +++ b/src/corelib/arch/sparc/qatomic32.s @@ -0,0 +1,103 @@ +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! +!! Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +!! All rights reserved. +!! Contact: Nokia Corporation (qt-info@nokia.com) +!! +!! This file is part of the QtGui module of the Qt Toolkit. +!! +!! $QT_BEGIN_LICENSE:LGPL$ +!! No Commercial Usage +!! This file contains pre-release code and may not be distributed. +!! You may use this file in accordance with the terms and conditions +!! contained in the Technology Preview License Agreement accompanying +!! this package. +!! +!! GNU Lesser General Public License Usage +!! Alternatively, this file may be used under the terms of the GNU Lesser +!! General Public License version 2.1 as published by the Free Software +!! Foundation and appearing in the file LICENSE.LGPL included in the +!! packaging of this file. Please review the following information to +!! ensure the GNU Lesser General Public License version 2.1 requirements +!! will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +!! +!! In addition, as a special exception, Nokia gives you certain additional +!! rights. These rights are described in the Nokia Qt LGPL Exception +!! version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +!! +!! If you have questions regarding the use of this file, please contact +!! Nokia at qt-info@nokia.com. +!! +!! +!! +!! +!! +!! +!! +!! +!! $QT_END_LICENSE$ +!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + .section ".text" + + .align 4 + .type q_atomic_trylock_int,#function + .global q_atomic_trylock_int +q_atomic_trylock_int: + sethi %hi(-2147483648),%o2 + swap [%o0],%o2 + retl + mov %o2,%o0 + .size q_atomic_trylock_int,.-q_atomic_trylock_int + + + + + .align 4 + .type q_atomic_trylock_ptr,#function + .global q_atomic_trylock_ptr +q_atomic_trylock_ptr: + mov -1, %o2 + swap [%o0], %o2 + retl + mov %o2, %o0 + .size q_atomic_trylock_ptr,.-q_atomic_trylock_ptr + + + + + .align 4 + .type q_atomic_unlock,#function + .global q_atomic_unlock +q_atomic_unlock: + stbar + retl + st %o1,[%o0] + .size q_atomic_unlock,.-q_atomic_unlock + + + + + .align 4 + .type q_atomic_set_int,#function + .global q_atomic_set_int +q_atomic_set_int: + swap [%o0],%o1 + stbar + retl + mov %o1,%o0 + .size q_atomic_set_int,.-q_atomic_set_int + + + + + .align 4 + .type q_atomic_set_ptr,#function + .global q_atomic_set_ptr +q_atomic_set_ptr: + swap [%o0],%o1 + stbar + retl + mov %o1,%o0 + .size q_atomic_set_ptr,.-q_atomic_set_ptr + diff --git a/src/corelib/arch/sparc/qatomic64.s b/src/corelib/arch/sparc/qatomic64.s new file mode 100644 index 0000000000..f826311da4 --- /dev/null +++ b/src/corelib/arch/sparc/qatomic64.s @@ -0,0 +1,327 @@ +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! +!! Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +!! All rights reserved. +!! Contact: Nokia Corporation (qt-info@nokia.com) +!! +!! This file is part of the QtGui module of the Qt Toolkit. +!! +!! $QT_BEGIN_LICENSE:LGPL$ +!! No Commercial Usage +!! This file contains pre-release code and may not be distributed. +!! You may use this file in accordance with the terms and conditions +!! contained in the Technology Preview License Agreement accompanying +!! this package. +!! +!! GNU Lesser General Public License Usage +!! Alternatively, this file may be used under the terms of the GNU Lesser +!! General Public License version 2.1 as published by the Free Software +!! Foundation and appearing in the file LICENSE.LGPL included in the +!! packaging of this file. Please review the following information to +!! ensure the GNU Lesser General Public License version 2.1 requirements +!! will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +!! +!! In addition, as a special exception, Nokia gives you certain additional +!! rights. These rights are described in the Nokia Qt LGPL Exception +!! version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +!! +!! If you have questions regarding the use of this file, please contact +!! Nokia at qt-info@nokia.com. +!! +!! +!! +!! +!! +!! +!! +!! +!! $QT_END_LICENSE$ +!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + .section ".text" + + .align 4 + .type q_atomic_test_and_set_int,#function + .global q_atomic_test_and_set_int +q_atomic_test_and_set_int: + cas [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_int,.-q_atomic_test_and_set_int + + .align 4 + .type q_atomic_test_and_set_acquire_int,#function + .global q_atomic_test_and_set_acquire_int +q_atomic_test_and_set_acquire_int: + cas [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + membar #LoadLoad | #LoadStore + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_acquire_int,.-q_atomic_test_and_set_acquire_int + + .align 4 + .type q_atomic_test_and_set_release_int,#function + .global q_atomic_test_and_set_release_int +q_atomic_test_and_set_release_int: + membar #LoadStore | #StoreStore + cas [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_release_int,.-q_atomic_test_and_set_release_int + + .align 4 + .type q_atomic_test_and_set_ptr,#function + .global q_atomic_test_and_set_ptr +q_atomic_test_and_set_ptr: + casx [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_ptr,.-q_atomic_test_and_set_ptr + + .align 4 + .type q_atomic_increment,#function + .global q_atomic_increment +q_atomic_increment: +q_atomic_increment_retry: + ld [%o0],%o3 + add %o3,1,%o4 + cas [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_increment_retry + nop + cmp %o4,-1 + clr %o0 + retl + movne %icc,1,%o0 + .size q_atomic_increment,.-q_atomic_increment + + .align 4 + .type q_atomic_decrement,#function + .global q_atomic_decrement +q_atomic_decrement: +q_atomic_decrement_retry: + ld [%o0],%o3 + add %o3,-1,%o4 + cas [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_decrement_retry + nop + cmp %o4,1 + clr %o0 + retl + movne %icc,1,%o0 + .size q_atomic_decrement,.-q_atomic_decrement + + .align 4 + .type q_atomic_set_int,#function + .global q_atomic_set_int +q_atomic_set_int: +q_atomic_set_int_retry: + ld [%o0],%o2 + cas [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_set_int_retry + nop + retl + mov %o1,%o0 + .size q_atomic_set_int,.-q_atomic_set_int + + .align 4 + .type q_atomic_set_ptr,#function + .global q_atomic_set_ptr +q_atomic_set_ptr: +q_atomic_set_ptr_retry: + ldx [%o0],%o2 + casx [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_set_ptr_retry + nop + retl + mov %o1,%o0 + .size q_atomic_set_ptr,.-q_atomic_set_ptr + + .align 4 + .type q_atomic_fetch_and_add_int,#function + .global q_atomic_fetch_and_add_int +q_atomic_fetch_and_add_int: +q_atomic_fetch_and_add_int_retry: + ld [%o0],%o3 + add %o3,%o1,%o4 + cas [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_int_retry + nop + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_int,.-q_atomic_fetch_and_add_int + + .align 4 + .type q_atomic_fetch_and_add_acquire_int,#function + .global q_atomic_fetch_and_add_acquire_int +q_atomic_fetch_and_add_acquire_int: +q_atomic_fetch_and_add_acquire_int_retry: + ld [%o0],%o3 + add %o3,%o1,%o4 + cas [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_acquire_int_retry + nop + membar #LoadLoad | #LoadStore + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_acquire_int,.-q_atomic_fetch_and_add_acquire_int + + .align 4 + .type q_atomic_fetch_and_add_release_int,#function + .global q_atomic_fetch_and_add_release_int +q_atomic_fetch_and_add_release_int: +q_atomic_fetch_and_add_release_int_retry: + membar #LoadStore | #StoreStore + ld [%o0],%o3 + add %o3,%o1,%o4 + cas [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_release_int_retry + nop + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_release_int,.-q_atomic_fetch_and_add_release_int + + .align 4 + .type q_atomic_fetch_and_store_acquire_int,#function + .global q_atomic_fetch_and_store_acquire_int +q_atomic_fetch_and_store_acquire_int: +q_atomic_fetch_and_store_acquire_int_retry: + ld [%o0],%o2 + cas [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_fetch_and_store_acquire_int_retry + nop + membar #LoadLoad | #LoadStore + retl + mov %o1,%o0 + .size q_atomic_fetch_and_store_acquire_int,.-q_atomic_fetch_and_store_acquire_int + + .align 4 + .type q_atomic_fetch_and_store_release_int,#function + .global q_atomic_fetch_and_store_release_int +q_atomic_fetch_and_store_release_int: +q_atomic_fetch_and_store_release_int_retry: + membar #LoadStore | #StoreStore + ld [%o0],%o2 + cas [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_fetch_and_store_release_int_retry + nop + retl + mov %o1,%o0 + .size q_atomic_fetch_and_store_release_int,.-q_atomic_fetch_and_store_release_int + + .align 4 + .type q_atomic_test_and_set_acquire_ptr,#function + .global q_atomic_test_and_set_acquire_ptr +q_atomic_test_and_set_acquire_ptr: + casx [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + membar #LoadLoad | #LoadStore + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_acquire_ptr,.-q_atomic_test_and_set_acquire_ptr + + .align 4 + .type q_atomic_test_and_set_release_ptr,#function + .global q_atomic_test_and_set_release_ptr +q_atomic_test_and_set_release_ptr: + membar #LoadStore | #StoreStore + casx [%o0],%o1,%o2 + cmp %o1,%o2 + clr %o0 + retl + move %icc,1,%o0 + .size q_atomic_test_and_set_release_ptr,.-q_atomic_test_and_set_release_ptr + + .align 4 + .type q_atomic_fetch_and_store_acquire_ptr,#function + .global q_atomic_fetch_and_store_acquire_ptr +q_atomic_fetch_and_store_acquire_ptr: +q_atomic_fetch_and_store_acquire_ptr_retry: + ldx [%o0],%o2 + casx [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_fetch_and_store_acquire_ptr_retry + nop + membar #LoadLoad | #LoadStore + retl + mov %o1,%o0 + .size q_atomic_fetch_and_store_acquire_ptr,.-q_atomic_fetch_and_store_acquire_ptr + + .align 4 + .type q_atomic_fetch_and_store_release_ptr,#function + .global q_atomic_fetch_and_store_release_ptr +q_atomic_fetch_and_store_release_ptr: +q_atomic_fetch_and_store_release_ptr_retry: + membar #LoadStore | #StoreStore + ldx [%o0],%o2 + casx [%o0],%o2,%o1 + cmp %o2,%o1 + bne q_atomic_fetch_and_store_release_ptr_retry + nop + retl + mov %o1,%o0 + .size q_atomic_fetch_and_store_release_ptr,.-q_atomic_fetch_and_store_release_ptr + + .align 4 + .type q_atomic_fetch_and_add_ptr,#function + .global q_atomic_fetch_and_add_ptr +q_atomic_fetch_and_add_ptr: +q_atomic_fetch_and_add_ptr_retry: + ldx [%o0],%o3 + add %o3,%o1,%o4 + casx [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_ptr_retry + nop + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_ptr,.-q_atomic_fetch_and_add_ptr + + .align 4 + .type q_atomic_fetch_and_add_acquire_ptr,#function + .global q_atomic_fetch_and_add_acquire_ptr +q_atomic_fetch_and_add_acquire_ptr: +q_atomic_fetch_and_add_acquire_ptr_retry: + ldx [%o0],%o3 + add %o3,%o1,%o4 + casx [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_acquire_ptr_retry + nop + membar #LoadLoad | #LoadStore + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_acquire_ptr,.-q_atomic_fetch_and_add_acquire_ptr + + .align 4 + .type q_atomic_fetch_and_add_release_ptr,#function + .global q_atomic_fetch_and_add_release_ptr +q_atomic_fetch_and_add_release_ptr: +q_atomic_fetch_and_add_release_ptr_retry: + membar #LoadStore | #StoreStore + ldx [%o0],%o3 + add %o3,%o1,%o4 + casx [%o0],%o3,%o4 + cmp %o3,%o4 + bne q_atomic_fetch_and_add_release_ptr_retry + nop + retl + mov %o3,%o0 + .size q_atomic_fetch_and_add_release_ptr,.-q_atomic_fetch_and_add_release_ptr diff --git a/src/corelib/arch/sparc/qatomic_sparc.cpp b/src/corelib/arch/sparc/qatomic_sparc.cpp new file mode 100644 index 0000000000..ec398e03b6 --- /dev/null +++ b/src/corelib/arch/sparc/qatomic_sparc.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +extern "C" { + +int q_atomic_trylock_int(volatile int *addr); +int q_atomic_trylock_ptr(volatile void *addr); + +Q_CORE_EXPORT int q_atomic_lock_int(volatile int *addr) +{ + int returnValue = q_atomic_trylock_int(addr); + + if (returnValue == INT_MIN) { + do { + // spin until we think we can succeed + do { + sched_yield(); + returnValue = *addr; + } while (returnValue == INT_MIN); + + // try again + returnValue = q_atomic_trylock_int(addr); + } while (returnValue == INT_MIN); + } + + return returnValue; +} + +Q_CORE_EXPORT int q_atomic_lock_ptr(volatile void *addr) +{ + int returnValue = q_atomic_trylock_ptr(addr); + + if (returnValue == -1) { + do { + // spin until we think we can succeed + do { + sched_yield(); + returnValue = *reinterpret_cast(addr); + } while (returnValue == -1); + + // try again + returnValue = q_atomic_trylock_ptr(addr); + } while (returnValue == -1); + } + + return returnValue; +} + +} // extern "C" diff --git a/src/corelib/arch/symbian/arch.pri b/src/corelib/arch/symbian/arch.pri new file mode 100644 index 0000000000..2e2a9b6aed --- /dev/null +++ b/src/corelib/arch/symbian/arch.pri @@ -0,0 +1,18 @@ +# +# Symbian architecture +# +SOURCES += $$QT_ARCH_CPP/qatomic_symbian.cpp \ + $$QT_ARCH_CPP/qatomic_generic_armv6.cpp \ + $$QT_ARCH_CPP/heap_hybrid.cpp \ + $$QT_ARCH_CPP/debugfunction.cpp \ + $$QT_ARCH_CPP/qt_heapsetup_symbian.cpp + +HEADERS += $$QT_ARCH_CPP/dla_p.h \ + $$QT_ARCH_CPP/heap_hybrid_p.h \ + $$QT_ARCH_CPP/common_p.h \ + $$QT_ARCH_CPP/page_alloc_p.h \ + $$QT_ARCH_CPP/slab_p.h \ + $$QT_ARCH_CPP/qt_hybridHeap_symbian_p.h + +exists($${EPOCROOT}epoc32/include/platform/u32std.h):DEFINES += QT_SYMBIAN_HAVE_U32STD_H +exists($${EPOCROOT}epoc32/include/platform/e32btrace.h):DEFINES += QT_SYMBIAN_HAVE_E32BTRACE_H diff --git a/src/corelib/arch/symbian/common_p.h b/src/corelib/arch/symbian/common_p.h new file mode 100644 index 0000000000..852646c250 --- /dev/null +++ b/src/corelib/arch/symbian/common_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __E32_COMMON_H__ +#define __E32_COMMON_H__ + +#ifdef __KERNEL_MODE__ +#include +#include +#include "u32std.h" +#else +#include +#include +#include +#include +#include +#include +#include +// backport of Symbian^4 allocator to Symbian^3 SDK does not contain u32exec.h +//#include +#endif + +GLREF_C void Panic(TCdtPanic aPanic); +GLDEF_C void PanicBadArrayIndex(); +GLREF_C TInt __DoConvertNum(TUint, TRadix, TUint, TUint8*&); +GLREF_C TInt __DoConvertNum(Uint64, TRadix, TUint, TUint8*&); + +#ifdef __KERNEL_MODE__ +GLREF_C void KernHeapFault(TCdtPanic aPanic); +GLREF_C void KHeapCheckThreadState(); +TInt StringLength(const TUint16* aPtr); +TInt StringLength(const TUint8* aPtr); + +#define STD_CLASS Kern +#define STRING_LENGTH(s) StringLength(s) +#define STRING_LENGTH_16(s) StringLength(s) +#define PANIC_CURRENT_THREAD(c,r) Kern::PanicCurrentThread(c, r) +#define __KERNEL_CHECK_RADIX(r) __ASSERT_ALWAYS(((r)==EDecimal)||((r)==EHex),Panic(EInvalidRadix)) +#define APPEND_BUF_SIZE 10 +#define APPEND_BUF_SIZE_64 20 +#define HEAP_PANIC(r) Kern::Printf("HEAP CORRUPTED %s %d", __FILE__, __LINE__), RHeapK::Fault(r) +#define GET_PAGE_SIZE(x) x = M::PageSizeInBytes() +#define DIVISION_BY_ZERO() FAULT() + +#ifdef _DEBUG +#define __CHECK_THREAD_STATE RHeapK::CheckThreadState() +#else +#define __CHECK_THREAD_STATE +#endif + +#else + +#define STD_CLASS User +#define STRING_LENGTH(s) User::StringLength(s) +#define STRING_LENGTH_16(s) User::StringLength(s) +#define PANIC_CURRENT_THREAD(c,r) User::Panic(c, r) +#define MEM_COMPARE_16 Mem::Compare +#define __KERNEL_CHECK_RADIX(r) +#define APPEND_BUF_SIZE 32 +#define APPEND_BUF_SIZE_64 64 +#define HEAP_PANIC(r) RDebug::Printf("HEAP CORRUPTED %s %d", __FILE__, __LINE__), Panic(r) +#define GET_PAGE_SIZE(x) UserHal::PageSizeInBytes(x) +#define DIVISION_BY_ZERO() User::RaiseException(EExcIntegerDivideByZero) +#define __CHECK_THREAD_STATE + +#endif // __KERNEL_MODE__ + +#endif diff --git a/src/corelib/arch/symbian/debugfunction.cpp b/src/corelib/arch/symbian/debugfunction.cpp new file mode 100644 index 0000000000..445f1063a8 --- /dev/null +++ b/src/corelib/arch/symbian/debugfunction.cpp @@ -0,0 +1,1143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt_hybridheap_symbian_p.h" + +#ifdef QT_USE_NEW_SYMBIAN_ALLOCATOR + +#define GM (&iGlobalMallocState) +#define __HEAP_CORRUPTED_TRACE(t,p,l) BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)t, (TUint32)p, (TUint32)l); +#define __HEAP_CORRUPTED_TEST(c,x, p,l) if (!c) { if (iFlags & (EMonitorMemory+ETraceAllocs) ) __HEAP_CORRUPTED_TRACE(this,p,l) HEAP_PANIC(x); } +#define __HEAP_CORRUPTED_TEST_STATIC(c,t,x,p,l) if (!c) { if (t && (t->iFlags & (EMonitorMemory+ETraceAllocs) )) __HEAP_CORRUPTED_TRACE(t,p,l) HEAP_PANIC(x); } + +TInt RHybridHeap::DebugFunction(TInt aFunc, TAny* a1, TAny* a2) +{ + TInt r = KErrNone; + switch(aFunc) + { + + case RAllocator::ECount: + struct HeapInfo info; + Lock(); + GetInfo(&info, NULL); + *(unsigned*)a1 = info.iFreeN; + r = info.iAllocN; + Unlock(); + break; + + case RAllocator::EMarkStart: + __DEBUG_ONLY(DoMarkStart()); + break; + + case RAllocator::EMarkEnd: + __DEBUG_ONLY( r = DoMarkEnd((TInt)a1) ); + break; + + case RAllocator::ECheck: + r = DoCheckHeap((SCheckInfo*)a1); + break; + + case RAllocator::ESetFail: + __DEBUG_ONLY(DoSetAllocFail((TAllocFail)(TInt)a1, (TInt)a2)); + break; + + case RHybridHeap::EGetFail: + __DEBUG_ONLY(r = iFailType); + break; + + case RHybridHeap::ESetBurstFail: +#if _DEBUG + { + SRAllocatorBurstFail* fail = (SRAllocatorBurstFail*) a2; + DoSetAllocFail((TAllocFail)(TInt)a1, fail->iRate, fail->iBurst); + } +#endif + break; + + case RHybridHeap::ECheckFailure: + // iRand will be incremented for each EFailNext, EBurstFailNext, + // EDeterministic and EBurstDeterministic failure. + r = iRand; + break; + + case RAllocator::ECopyDebugInfo: + { + TInt nestingLevel = ((SDebugCell*)a1)[-1].nestingLevel; + ((SDebugCell*)a2)[-1].nestingLevel = nestingLevel; + break; + } + + case RHybridHeap::EGetSize: + { + r = iChunkSize - sizeof(RHybridHeap); + break; + } + + case RHybridHeap::EGetMaxLength: + { + r = iMaxLength; + break; + } + + case RHybridHeap::EGetBase: + { + *(TAny**)a1 = iBase; + break; + } + + case RHybridHeap::EAlignInteger: + { + r = _ALIGN_UP((TInt)a1, iAlign); + break; + } + + case RHybridHeap::EAlignAddr: + { + *(TAny**)a2 = (TAny*)_ALIGN_UP((TLinAddr)a1, iAlign); + break; + } + + case RHybridHeap::EWalk: + struct HeapInfo hinfo; + SWalkInfo winfo; + Lock(); + winfo.iFunction = (TWalkFunc)a1; + winfo.iParam = a2; + winfo.iHeap = (RHybridHeap*)this; + GetInfo(&hinfo, &winfo); + Unlock(); + break; + +#ifndef __KERNEL_MODE__ + + case RHybridHeap::EHybridHeap: + { + if ( !a1 ) + return KErrGeneral; + STestCommand* cmd = (STestCommand*)a1; + switch ( cmd->iCommand ) + { + case EGetConfig: + cmd->iConfig.iSlabBits = iSlabConfigBits; + cmd->iConfig.iDelayedSlabThreshold = iPageThreshold; + cmd->iConfig.iPagePower = iPageThreshold; + break; + + case ESetConfig: + // + // New configuration data for slab and page allocator. + // Reset heap to get data into use + // +#if USE_HYBRID_HEAP + iSlabConfigBits = cmd->iConfig.iSlabBits & 0x3fff; + iSlabInitThreshold = cmd->iConfig.iDelayedSlabThreshold; + iPageThreshold = (cmd->iConfig.iPagePower & 0x1f); + Reset(); +#endif + break; + + case EHeapMetaData: + cmd->iData = this; + break; + + case ETestData: + iTestData = cmd->iData; + break; + + default: + return KErrNotSupported; + + } + + break; + } +#endif // __KERNEL_MODE + + default: + return KErrNotSupported; + + } + return r; +} + +void RHybridHeap::Walk(SWalkInfo* aInfo, TAny* aBfr, TInt aLth, TCellType aBfrType, TAllocatorType aAllocatorType) +{ + // + // This function is always called from RHybridHeap::GetInfo. + // Actual walk function is called if SWalkInfo pointer is defined + // + // + if ( aInfo ) + { +#ifdef __KERNEL_MODE__ + (void)aAllocatorType; +#if defined(_DEBUG) + if ( aBfrType == EGoodAllocatedCell ) + aInfo->iFunction(aInfo->iParam, aBfrType, ((TUint8*)aBfr+EDebugHdrSize), (aLth-EDebugHdrSize) ); + else + aInfo->iFunction(aInfo->iParam, aBfrType, aBfr, aLth ); +#else + aInfo->iFunction(aInfo->iParam, aBfrType, aBfr, aLth ); +#endif + +#else // __KERNEL_MODE__ + + if ( aAllocatorType & (EFullSlab + EPartialFullSlab + EEmptySlab + ESlabSpare) ) + { + if ( aInfo->iHeap ) + { + TUint32 dummy; + TInt npages; + aInfo->iHeap->DoCheckSlab((slab*)aBfr, aAllocatorType); + __HEAP_CORRUPTED_TEST_STATIC(aInfo->iHeap->CheckBitmap(Floor(aBfr, PAGESIZE), PAGESIZE, dummy, npages), + aInfo->iHeap, ETHeapBadCellAddress, aBfr, aLth); + } + if ( aAllocatorType & EPartialFullSlab ) + WalkPartialFullSlab(aInfo, (slab*)aBfr, aBfrType, aLth); + else if ( aAllocatorType & EFullSlab ) + WalkFullSlab(aInfo, (slab*)aBfr, aBfrType, aLth); + } +#if defined(_DEBUG) + else if ( aBfrType == EGoodAllocatedCell ) + aInfo->iFunction(aInfo->iParam, aBfrType, ((TUint8*)aBfr+EDebugHdrSize), (aLth-EDebugHdrSize) ); + else + aInfo->iFunction(aInfo->iParam, aBfrType, aBfr, aLth ); +#else + else + aInfo->iFunction(aInfo->iParam, aBfrType, aBfr, aLth ); +#endif + +#endif // __KERNEL_MODE + } +} + +#ifndef __KERNEL_MODE__ +void RHybridHeap::WalkPartialFullSlab(SWalkInfo* aInfo, slab* aSlab, TCellType /*aBfrType*/, TInt /*aLth*/) +{ + if ( aInfo ) + { + // + // Build bitmap of free buffers in the partial full slab + // + TUint32 bitmap[4]; + __HEAP_CORRUPTED_TEST_STATIC( (aInfo->iHeap != NULL), aInfo->iHeap, ETHeapBadCellAddress, 0, aSlab); + aInfo->iHeap->BuildPartialSlabBitmap(bitmap, aSlab); + // + // Find used (allocated) buffers from iPartial full slab + // + TUint32 h = aSlab->iHeader; + TUint32 size = SlabHeaderSize(h); + TUint32 count = KMaxSlabPayload / size; // Total buffer count in slab + TUint32 i = 0; + TUint32 ix = 0; + TUint32 bit = 1; + + while ( i < count ) + { + + if ( bitmap[ix] & bit ) + { + aInfo->iFunction(aInfo->iParam, EGoodFreeCell, &aSlab->iPayload[i*size], size ); + } + else + { +#if defined(_DEBUG) + aInfo->iFunction(aInfo->iParam, EGoodAllocatedCell, (&aSlab->iPayload[i*size]+EDebugHdrSize), (size-EDebugHdrSize) ); +#else + aInfo->iFunction(aInfo->iParam, EGoodAllocatedCell, &aSlab->iPayload[i*size], size ); +#endif + } + bit <<= 1; + if ( bit == 0 ) + { + bit = 1; + ix ++; + } + + i ++; + } + } + +} + +void RHybridHeap::WalkFullSlab(SWalkInfo* aInfo, slab* aSlab, TCellType aBfrType, TInt /*aLth*/) +{ + if ( aInfo ) + { + TUint32 h = aSlab->iHeader; + TUint32 size = SlabHeaderSize(h); + TUint32 count = (SlabHeaderUsedm4(h) + 4) / size; + TUint32 i = 0; + while ( i < count ) + { +#if defined(_DEBUG) + if ( aBfrType == EGoodAllocatedCell ) + aInfo->iFunction(aInfo->iParam, aBfrType, (&aSlab->iPayload[i*size]+EDebugHdrSize), (size-EDebugHdrSize) ); + else + aInfo->iFunction(aInfo->iParam, aBfrType, &aSlab->iPayload[i*size], size ); +#else + aInfo->iFunction(aInfo->iParam, aBfrType, &aSlab->iPayload[i*size], size ); +#endif + i ++; + } + } +} + +void RHybridHeap::BuildPartialSlabBitmap(TUint32* aBitmap, slab* aSlab, TAny* aBfr) +{ + // + // Build a bitmap of free buffers in a partial full slab + // + TInt i; + TUint32 bit = 0; + TUint32 index; + TUint32 h = aSlab->iHeader; + TUint32 used = SlabHeaderUsedm4(h)+4; + TUint32 size = SlabHeaderSize(h); + TInt count = (KMaxSlabPayload / size); + TInt free_count = count - (used / size); // Total free buffer count in slab + aBitmap[0] = 0, aBitmap[1] = 0, aBitmap[2] = 0, aBitmap[3] = 0; + TUint32 offs = (h & 0xff) << 2; + + // + // Process first buffer in partial slab free buffer chain + // + while ( offs ) + { + unsigned char* p = (unsigned char*)Offset(aSlab, offs); + __HEAP_CORRUPTED_TEST( (sizeof(slabhdr) <= offs), ETHeapBadCellAddress, p, aSlab); + offs -= sizeof(slabhdr); + __HEAP_CORRUPTED_TEST( (offs % size == 0), ETHeapBadCellAddress, p, aSlab); + index = (offs / size); // Bit index in bitmap + i = 0; + while ( i < 4 ) + { + if ( index < 32 ) + { + bit = (1 << index); + break; + } + index -= 32; + i ++; + } + + __HEAP_CORRUPTED_TEST( ((aBitmap[i] & bit) == 0), ETHeapBadCellAddress, p, aSlab); // Buffer already in chain + + aBitmap[i] |= bit; + free_count --; + offs = ((unsigned)*p) << 2; // Next in free chain + } + + __HEAP_CORRUPTED_TEST( (free_count >= 0), ETHeapBadCellAddress, aBfr, aSlab); // free buffer count/size mismatch + // + // Process next rest of the free buffers which are in the + // wilderness (at end of the slab) + // + index = count - 1; + i = index / 32; + index = index % 32; + while ( free_count && (i >= 0)) + { + bit = (1 << index); + __HEAP_CORRUPTED_TEST( ((aBitmap[i] & bit) == 0), ETHeapBadCellAddress, aBfr, aSlab); // Buffer already in chain + aBitmap[i] |= bit; + if ( index ) + index --; + else + { + index = 31; + i --; + } + free_count --; + } + + if ( aBfr ) // Assure that specified buffer does NOT exist in partial slab free buffer chain + { + offs = LowBits(aBfr, SLABSIZE); + __HEAP_CORRUPTED_TEST( (sizeof(slabhdr) <= offs), ETHeapBadCellAddress, aBfr, aSlab); + offs -= sizeof(slabhdr); + __HEAP_CORRUPTED_TEST( ((offs % size) == 0), ETHeapBadCellAddress, aBfr, aSlab); + index = (offs / size); // Bit index in bitmap + i = 0; + while ( i < 4 ) + { + if ( index < 32 ) + { + bit = (1 << index); + break; + } + index -= 32; + i ++; + } + __HEAP_CORRUPTED_TEST( ((aBitmap[i] & bit) == 0), ETHeapBadCellAddress, aBfr, aSlab); // Buffer already in chain + } +} + +#endif // __KERNEL_MODE__ + +void RHybridHeap::WalkCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen) +{ + (void)aCell; + SHeapCellInfo& info = *(SHeapCellInfo*)aPtr; + switch(aType) + { + case EGoodAllocatedCell: + { + ++info.iTotalAlloc; + info.iTotalAllocSize += aLen; +#if defined(_DEBUG) + RHybridHeap& h = *info.iHeap; + SDebugCell* DbgCell = (SDebugCell*)((TUint8*)aCell-EDebugHdrSize); + if ( DbgCell->nestingLevel == h.iNestingLevel ) + { + if (++info.iLevelAlloc==1) + info.iStranded = DbgCell; +#ifdef __KERNEL_MODE__ + if (KDebugNum(KSERVER) || KDebugNum(KTESTFAST)) + { + Kern::Printf("LEAKED KERNEL HEAP CELL @ %08x : len=%d", aCell, aLen); + TLinAddr base = ((TLinAddr)aCell)&~0x0f; + TLinAddr end = ((TLinAddr)aCell)+(TLinAddr)aLen; + while(baseiCount; + TInt actual = aInfo->iAll ? info.iTotalAlloc : info.iLevelAlloc; + if (actual!=expected && !iTestData) + { +#ifdef __KERNEL_MODE__ + Kern::Fault("KERN-ALLOC COUNT", (expected<<16)|actual ); +#else + User::Panic(_L("ALLOC COUNT"), (expected<<16)|actual ); +#endif + } +#endif + return KErrNone; +} + +#ifdef _DEBUG +void RHybridHeap::DoMarkStart() +{ + if (iNestingLevel==0) + iAllocCount=0; + iNestingLevel++; +} + +TUint32 RHybridHeap::DoMarkEnd(TInt aExpected) +{ + if (iNestingLevel==0) + return 0; + SHeapCellInfo info; + SHeapCellInfo* p = iTestData ? (SHeapCellInfo*)iTestData : &info; + memclr(p, sizeof(info)); + p->iHeap = this; + struct HeapInfo hinfo; + SWalkInfo winfo; + Lock(); + winfo.iFunction = WalkCheckCell; + winfo.iParam = p; + winfo.iHeap = (RHybridHeap*)this; + GetInfo(&hinfo, &winfo); + Unlock(); + + if (p->iLevelAlloc != aExpected && !iTestData) + return (TUint32)(p->iStranded + 1); + if (--iNestingLevel == 0) + iAllocCount = 0; + return 0; +} + +void RHybridHeap::DoSetAllocFail(TAllocFail aType, TInt aRate) +{// Default to a burst mode of 1, as aType may be a burst type. + DoSetAllocFail(aType, aRate, 1); +} + +void ResetAllocCellLevels(TAny* aPtr, RHybridHeap::TCellType aType, TAny* aCell, TInt aLen) +{ + (void)aPtr; + (void)aLen; + + if (aType == RHybridHeap::EGoodAllocatedCell) + { + RHybridHeap::SDebugCell* DbgCell = (RHybridHeap::SDebugCell*)((TUint8*)aCell-RHybridHeap::EDebugHdrSize); + DbgCell->nestingLevel = 0; + } +} + +// Don't change as the ETHeapBadDebugFailParameter check below and the API +// documentation rely on this being 16 for RHybridHeap. +LOCAL_D const TInt KBurstFailRateShift = 16; +LOCAL_D const TInt KBurstFailRateMask = (1 << KBurstFailRateShift) - 1; + +void RHybridHeap::DoSetAllocFail(TAllocFail aType, TInt aRate, TUint aBurst) +{ + if (aType==EReset) + { + // reset levels of all allocated cells to 0 + // this should prevent subsequent tests failing unnecessarily + iFailed = EFalse; // Reset for ECheckFailure relies on this. + struct HeapInfo hinfo; + SWalkInfo winfo; + Lock(); + winfo.iFunction = (TWalkFunc)&ResetAllocCellLevels; + winfo.iParam = NULL; + winfo.iHeap = (RHybridHeap*)this; + GetInfo(&hinfo, &winfo); + Unlock(); + // reset heap allocation mark as well + iNestingLevel=0; + iAllocCount=0; + aType=ENone; + } + + switch (aType) + { + case EBurstRandom: + case EBurstTrueRandom: + case EBurstDeterministic: + case EBurstFailNext: + // If the fail type is a burst type then iFailRate is split in 2: + // the 16 lsbs are the fail rate and the 16 msbs are the burst length. + if (TUint(aRate) > (TUint)KMaxTUint16 || aBurst > KMaxTUint16) + HEAP_PANIC(ETHeapBadDebugFailParameter); + + iFailed = EFalse; + iFailType = aType; + iFailRate = (aRate == 0) ? 1 : aRate; + iFailAllocCount = -iFailRate; + iFailRate = iFailRate | (aBurst << KBurstFailRateShift); + break; + + default: + iFailed = EFalse; + iFailType = aType; + iFailRate = (aRate == 0) ? 1 : aRate; // A rate of <1 is meaningless + iFailAllocCount = 0; + break; + } + + // Set up iRand for either: + // - random seed value, or + // - a count of the number of failures so far. + iRand = 0; +#ifndef __KERNEL_MODE__ + switch (iFailType) + { + case ETrueRandom: + case EBurstTrueRandom: + { + TTime time; + time.HomeTime(); + TInt64 seed = time.Int64(); + iRand = Math::Rand(seed); + break; + } + case ERandom: + case EBurstRandom: + { + TInt64 seed = 12345; + iRand = Math::Rand(seed); + break; + } + default: + break; + } +#endif +} + +TBool RHybridHeap::CheckForSimulatedAllocFail() +// +// Check to see if the user has requested simulated alloc failure, and if so possibly +// Return ETrue indicating a failure. +// +{ + // For burst mode failures iFailRate is shared + TUint16 rate = (TUint16)(iFailRate & KBurstFailRateMask); + TUint16 burst = (TUint16)(iFailRate >> KBurstFailRateShift); + TBool r = EFalse; + switch (iFailType) + { +#ifndef __KERNEL_MODE__ + case ERandom: + case ETrueRandom: + if (++iFailAllocCount>=iFailRate) + { + iFailAllocCount=0; + if (!iFailed) // haven't failed yet after iFailRate allocations so fail now + return(ETrue); + iFailed=EFalse; + } + else + { + if (!iFailed) + { + TInt64 seed=iRand; + iRand=Math::Rand(seed); + if (iRand%iFailRate==0) + { + iFailed=ETrue; + return(ETrue); + } + } + } + break; + + case EBurstRandom: + case EBurstTrueRandom: + if (++iFailAllocCount < 0) + { + // We haven't started failing yet so should we now? + TInt64 seed = iRand; + iRand = Math::Rand(seed); + if (iRand % rate == 0) + {// Fail now. Reset iFailAllocCount so we fail burst times + iFailAllocCount = 0; + r = ETrue; + } + } + else + { + if (iFailAllocCount < burst) + {// Keep failing for burst times + r = ETrue; + } + else + {// We've now failed burst times so start again. + iFailAllocCount = -(rate - 1); + } + } + break; +#endif + case EDeterministic: + if (++iFailAllocCount%iFailRate==0) + { + r=ETrue; + iRand++; // Keep count of how many times we have failed + } + break; + + case EBurstDeterministic: + // This will fail burst number of times, every rate attempts. + if (++iFailAllocCount >= 0) + { + if (iFailAllocCount == burst - 1) + {// This is the burst time we have failed so make it the last by + // reseting counts so we next fail after rate attempts. + iFailAllocCount = -rate; + } + r = ETrue; + iRand++; // Keep count of how many times we have failed + } + break; + + case EFailNext: + if ((++iFailAllocCount%iFailRate)==0) + { + iFailType=ENone; + r=ETrue; + iRand++; // Keep count of how many times we have failed + } + break; + + case EBurstFailNext: + if (++iFailAllocCount >= 0) + { + if (iFailAllocCount == burst - 1) + {// This is the burst time we have failed so make it the last. + iFailType = ENone; + } + r = ETrue; + iRand++; // Keep count of how many times we have failed + } + break; + + default: + break; + } + return r; +} + +#endif // DEBUG + +// +// Methods for Doug Lea allocator detailed check +// + +void RHybridHeap::DoCheckAnyChunk(mstate m, mchunkptr p) +{ + __HEAP_CORRUPTED_TEST(((IS_ALIGNED(CHUNK2MEM(p))) || (p->iHead == FENCEPOST_HEAD)), ETHeapBadCellAddress, p, 0); + (void)m; +} + +/* Check properties of iTop chunk */ +void RHybridHeap::DoCheckTopChunk(mstate m, mchunkptr p) +{ + msegmentptr sp = &m->iSeg; + size_t sz = CHUNKSIZE(p); + __HEAP_CORRUPTED_TEST((sp != 0), ETHeapBadCellAddress, p, 0); + __HEAP_CORRUPTED_TEST(((IS_ALIGNED(CHUNK2MEM(p))) || (p->iHead == FENCEPOST_HEAD)), ETHeapBadCellAddress, p,0); + __HEAP_CORRUPTED_TEST((sz == m->iTopSize), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((sz > 0), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((sz == ((sp->iBase + sp->iSize) - (TUint8*)p) - TOP_FOOT_SIZE), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((PINUSE(p)), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((!NEXT_PINUSE(p)), ETHeapBadCellAddress,p,0); +} + +/* Check properties of inuse chunks */ +void RHybridHeap::DoCheckInuseChunk(mstate m, mchunkptr p) +{ + DoCheckAnyChunk(m, p); + __HEAP_CORRUPTED_TEST((CINUSE(p)), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((NEXT_PINUSE(p)), ETHeapBadCellAddress,p,0); + /* If not PINUSE and not mmapped, previous chunk has OK offset */ + __HEAP_CORRUPTED_TEST((PINUSE(p) || NEXT_CHUNK(PREV_CHUNK(p)) == p), ETHeapBadCellAddress,p,0); +} + +/* Check properties of free chunks */ +void RHybridHeap::DoCheckFreeChunk(mstate m, mchunkptr p) +{ + size_t sz = p->iHead & ~(PINUSE_BIT|CINUSE_BIT); + mchunkptr next = CHUNK_PLUS_OFFSET(p, sz); + DoCheckAnyChunk(m, p); + __HEAP_CORRUPTED_TEST((!CINUSE(p)), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((!NEXT_PINUSE(p)), ETHeapBadCellAddress,p,0); + if (p != m->iDv && p != m->iTop) + { + if (sz >= MIN_CHUNK_SIZE) + { + __HEAP_CORRUPTED_TEST(((sz & CHUNK_ALIGN_MASK) == 0), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((IS_ALIGNED(CHUNK2MEM(p))), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((next->iPrevFoot == sz), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((PINUSE(p)), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST( (next == m->iTop || CINUSE(next)), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((p->iFd->iBk == p), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((p->iBk->iFd == p), ETHeapBadCellAddress,p,0); + } + else /* markers are always of size SIZE_T_SIZE */ + __HEAP_CORRUPTED_TEST((sz == SIZE_T_SIZE), ETHeapBadCellAddress,p,0); + } +} + +/* Check properties of malloced chunks at the point they are malloced */ +void RHybridHeap::DoCheckMallocedChunk(mstate m, void* mem, size_t s) +{ + if (mem != 0) + { + mchunkptr p = MEM2CHUNK(mem); + size_t sz = p->iHead & ~(PINUSE_BIT|CINUSE_BIT); + DoCheckInuseChunk(m, p); + __HEAP_CORRUPTED_TEST(((sz & CHUNK_ALIGN_MASK) == 0), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((sz >= MIN_CHUNK_SIZE), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((sz >= s), ETHeapBadCellAddress,p,0); + /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ + __HEAP_CORRUPTED_TEST((sz < (s + MIN_CHUNK_SIZE)), ETHeapBadCellAddress,p,0); + } +} + +/* Check a tree and its subtrees. */ +void RHybridHeap::DoCheckTree(mstate m, tchunkptr t) +{ + tchunkptr head = 0; + tchunkptr u = t; + bindex_t tindex = t->iIndex; + size_t tsize = CHUNKSIZE(t); + bindex_t idx; + DoComputeTreeIndex(tsize, idx); + __HEAP_CORRUPTED_TEST((tindex == idx), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((tsize >= MIN_LARGE_SIZE), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((tsize >= MINSIZE_FOR_TREE_INDEX(idx)), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST(((idx == NTREEBINS-1) || (tsize < MINSIZE_FOR_TREE_INDEX((idx+1)))), ETHeapBadCellAddress,u,0); + + do + { /* traverse through chain of same-sized nodes */ + DoCheckAnyChunk(m, ((mchunkptr)u)); + __HEAP_CORRUPTED_TEST((u->iIndex == tindex), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((CHUNKSIZE(u) == tsize), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((!CINUSE(u)), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((!NEXT_PINUSE(u)), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((u->iFd->iBk == u), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((u->iBk->iFd == u), ETHeapBadCellAddress,u,0); + if (u->iParent == 0) + { + __HEAP_CORRUPTED_TEST((u->iChild[0] == 0), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((u->iChild[1] == 0), ETHeapBadCellAddress,u,0); + } + else + { + __HEAP_CORRUPTED_TEST((head == 0), ETHeapBadCellAddress,u,0); /* only one node on chain has iParent */ + head = u; + __HEAP_CORRUPTED_TEST((u->iParent != u), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST( (u->iParent->iChild[0] == u || + u->iParent->iChild[1] == u || + *((tbinptr*)(u->iParent)) == u), ETHeapBadCellAddress,u,0); + if (u->iChild[0] != 0) + { + __HEAP_CORRUPTED_TEST((u->iChild[0]->iParent == u), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((u->iChild[0] != u), ETHeapBadCellAddress,u,0); + DoCheckTree(m, u->iChild[0]); + } + if (u->iChild[1] != 0) + { + __HEAP_CORRUPTED_TEST((u->iChild[1]->iParent == u), ETHeapBadCellAddress,u,0); + __HEAP_CORRUPTED_TEST((u->iChild[1] != u), ETHeapBadCellAddress,u,0); + DoCheckTree(m, u->iChild[1]); + } + if (u->iChild[0] != 0 && u->iChild[1] != 0) + { + __HEAP_CORRUPTED_TEST((CHUNKSIZE(u->iChild[0]) < CHUNKSIZE(u->iChild[1])), ETHeapBadCellAddress,u,0); + } + } + u = u->iFd; + } + while (u != t); + __HEAP_CORRUPTED_TEST((head != 0), ETHeapBadCellAddress,u,0); +} + +/* Check all the chunks in a treebin. */ +void RHybridHeap::DoCheckTreebin(mstate m, bindex_t i) +{ + tbinptr* tb = TREEBIN_AT(m, i); + tchunkptr t = *tb; + int empty = (m->iTreeMap & (1U << i)) == 0; + if (t == 0) + __HEAP_CORRUPTED_TEST((empty), ETHeapBadCellAddress,t,0); + if (!empty) + DoCheckTree(m, t); +} + +/* Check all the chunks in a smallbin. */ +void RHybridHeap::DoCheckSmallbin(mstate m, bindex_t i) +{ + sbinptr b = SMALLBIN_AT(m, i); + mchunkptr p = b->iBk; + unsigned int empty = (m->iSmallMap & (1U << i)) == 0; + if (p == b) + __HEAP_CORRUPTED_TEST((empty), ETHeapBadCellAddress,p,0); + if (!empty) + { + for (; p != b; p = p->iBk) + { + size_t size = CHUNKSIZE(p); + mchunkptr q; + /* each chunk claims to be free */ + DoCheckFreeChunk(m, p); + /* chunk belongs in bin */ + __HEAP_CORRUPTED_TEST((SMALL_INDEX(size) == i), ETHeapBadCellAddress,p,0); + __HEAP_CORRUPTED_TEST((p->iBk == b || CHUNKSIZE(p->iBk) == CHUNKSIZE(p)), ETHeapBadCellAddress,p,0); + /* chunk is followed by an inuse chunk */ + q = NEXT_CHUNK(p); + if (q->iHead != FENCEPOST_HEAD) + DoCheckInuseChunk(m, q); + } + } +} + +/* Find x in a bin. Used in other check functions. */ +TInt RHybridHeap::BinFind(mstate m, mchunkptr x) +{ + size_t size = CHUNKSIZE(x); + if (IS_SMALL(size)) + { + bindex_t sidx = SMALL_INDEX(size); + sbinptr b = SMALLBIN_AT(m, sidx); + if (SMALLMAP_IS_MARKED(m, sidx)) + { + mchunkptr p = b; + do + { + if (p == x) + return 1; + } + while ((p = p->iFd) != b); + } + } + else + { + bindex_t tidx; + DoComputeTreeIndex(size, tidx); + if (TREEMAP_IS_MARKED(m, tidx)) + { + tchunkptr t = *TREEBIN_AT(m, tidx); + size_t sizebits = size << LEFTSHIFT_FOR_TREE_INDEX(tidx); + while (t != 0 && CHUNKSIZE(t) != size) + { + t = t->iChild[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + sizebits <<= 1; + } + if (t != 0) + { + tchunkptr u = t; + do + { + if (u == (tchunkptr)x) + return 1; + } + while ((u = u->iFd) != t); + } + } + } + return 0; +} + +/* Traverse each chunk and check it; return total */ +size_t RHybridHeap::TraverseAndCheck(mstate m) +{ + size_t sum = 0; + msegmentptr s = &m->iSeg; + sum += m->iTopSize + TOP_FOOT_SIZE; + mchunkptr q = ALIGN_AS_CHUNK(s->iBase); + mchunkptr lastq = 0; + __HEAP_CORRUPTED_TEST((PINUSE(q)), ETHeapBadCellAddress,q,0); + while (q != m->iTop && q->iHead != FENCEPOST_HEAD) + { + sum += CHUNKSIZE(q); + if (CINUSE(q)) + { + __HEAP_CORRUPTED_TEST((!BinFind(m, q)), ETHeapBadCellAddress,q,0); + DoCheckInuseChunk(m, q); + } + else + { + __HEAP_CORRUPTED_TEST((q == m->iDv || BinFind(m, q)), ETHeapBadCellAddress,q,0); + __HEAP_CORRUPTED_TEST((lastq == 0 || CINUSE(lastq)), ETHeapBadCellAddress,q,0); /* Not 2 consecutive free */ + DoCheckFreeChunk(m, q); + } + lastq = q; + q = NEXT_CHUNK(q); + } + return sum; +} + +/* Check all properties of malloc_state. */ +void RHybridHeap::DoCheckMallocState(mstate m) +{ + bindex_t i; +// size_t total; + /* check bins */ + for (i = 0; i < NSMALLBINS; ++i) + DoCheckSmallbin(m, i); + for (i = 0; i < NTREEBINS; ++i) + DoCheckTreebin(m, i); + + if (m->iDvSize != 0) + { /* check iDv chunk */ + DoCheckAnyChunk(m, m->iDv); + __HEAP_CORRUPTED_TEST((m->iDvSize == CHUNKSIZE(m->iDv)), ETHeapBadCellAddress,m->iDv,0); + __HEAP_CORRUPTED_TEST((m->iDvSize >= MIN_CHUNK_SIZE), ETHeapBadCellAddress,m->iDv,0); + __HEAP_CORRUPTED_TEST((BinFind(m, m->iDv) == 0), ETHeapBadCellAddress,m->iDv,0); + } + + if (m->iTop != 0) + { /* check iTop chunk */ + DoCheckTopChunk(m, m->iTop); + __HEAP_CORRUPTED_TEST((m->iTopSize == CHUNKSIZE(m->iTop)), ETHeapBadCellAddress,m->iTop,0); + __HEAP_CORRUPTED_TEST((m->iTopSize > 0), ETHeapBadCellAddress,m->iTop,0); + __HEAP_CORRUPTED_TEST((BinFind(m, m->iTop) == 0), ETHeapBadCellAddress,m->iTop,0); + } + +// total = + TraverseAndCheck(m); +} + +#ifndef __KERNEL_MODE__ +// +// Methods for Slab allocator detailed check +// +void RHybridHeap::DoCheckSlabTree(slab** aS, TBool aPartialPage) +{ + slab* s = *aS; + if (!s) + return; + + TUint size = SlabHeaderSize(s->iHeader); + slab** parent = aS; + slab** child2 = &s->iChild2; + + while ( s ) + { + __HEAP_CORRUPTED_TEST((s->iParent == parent), ETHeapBadCellAddress,s,SLABSIZE); + __HEAP_CORRUPTED_TEST((!s->iChild1 || s < s->iChild1), ETHeapBadCellAddress,s,SLABSIZE); + __HEAP_CORRUPTED_TEST((!s->iChild2 || s < s->iChild2), ETHeapBadCellAddress,s,SLABSIZE); + + if ( aPartialPage ) + { + if ( s->iChild1 ) + size = SlabHeaderSize(s->iChild1->iHeader); + } + else + { + __HEAP_CORRUPTED_TEST((SlabHeaderSize(s->iHeader) == size), ETHeapBadCellAddress,s,SLABSIZE); + } + parent = &s->iChild1; + s = s->iChild1; + + } + + parent = child2; + s = *child2; + + while ( s ) + { + __HEAP_CORRUPTED_TEST((s->iParent == parent), ETHeapBadCellAddress,s,SLABSIZE); + __HEAP_CORRUPTED_TEST((!s->iChild1 || s < s->iChild1), ETHeapBadCellAddress,s,SLABSIZE); + __HEAP_CORRUPTED_TEST((!s->iChild2 || s < s->iChild2), ETHeapBadCellAddress,s,SLABSIZE); + + if ( aPartialPage ) + { + if ( s->iChild2 ) + size = SlabHeaderSize(s->iChild2->iHeader); + } + else + { + __HEAP_CORRUPTED_TEST((SlabHeaderSize(s->iHeader) == size), ETHeapBadCellAddress,s,SLABSIZE); + } + parent = &s->iChild2; + s = s->iChild2; + + } + +} + +void RHybridHeap::DoCheckSlabTrees() +{ + for (TInt i = 0; i < (MAXSLABSIZE>>2); ++i) + DoCheckSlabTree(&iSlabAlloc[i].iPartial, EFalse); + DoCheckSlabTree(&iPartialPage, ETrue); +} + +void RHybridHeap::DoCheckSlab(slab* aSlab, TAllocatorType aSlabType, TAny* aBfr) +{ + if ( (aSlabType == ESlabSpare) || (aSlabType == EEmptySlab) ) + return; + + unsigned h = aSlab->iHeader; + __HEAP_CORRUPTED_TEST((ZEROBITS(h)), ETHeapBadCellAddress,aBfr,aSlab); + unsigned used = SlabHeaderUsedm4(h)+4; + unsigned size = SlabHeaderSize(h); + __HEAP_CORRUPTED_TEST( (used < SLABSIZE),ETHeapBadCellAddress, aBfr, aSlab); + __HEAP_CORRUPTED_TEST( ((size > 3 ) && (size <= MAXSLABSIZE)), ETHeapBadCellAddress,aBfr,aSlab); + unsigned count = 0; + + switch ( aSlabType ) + { + case EFullSlab: + count = (KMaxSlabPayload / size ); + __HEAP_CORRUPTED_TEST((used == count*size), ETHeapBadCellAddress,aBfr,aSlab); + __HEAP_CORRUPTED_TEST((HeaderFloating(h)), ETHeapBadCellAddress,aBfr,aSlab); + break; + + case EPartialFullSlab: + __HEAP_CORRUPTED_TEST(((used % size)==0),ETHeapBadCellAddress,aBfr,aSlab); + __HEAP_CORRUPTED_TEST(((SlabHeaderFree(h) == 0) || (((SlabHeaderFree(h)<<2)-sizeof(slabhdr)) % SlabHeaderSize(h) == 0)), + ETHeapBadCellAddress,aBfr,aSlab); + break; + + default: + break; + + } +} + +// +// Check that committed size in heap equals number of pages in bitmap +// plus size of Doug Lea region +// +void RHybridHeap::DoCheckCommittedSize(TInt aNPages, mstate aM) +{ + TInt total_committed = (aNPages * iPageSize) + aM->iSeg.iSize + (iBase - (TUint8*)this); + __HEAP_CORRUPTED_TEST((total_committed == iChunkSize), ETHeapBadCellAddress,total_committed,iChunkSize); +} + +#endif // __KERNEL_MODE__ + +#endif /* QT_USE_NEW_SYMBIAN_ALLOCATOR */ diff --git a/src/corelib/arch/symbian/dla_p.h b/src/corelib/arch/symbian/dla_p.h new file mode 100644 index 0000000000..c2fa99a087 --- /dev/null +++ b/src/corelib/arch/symbian/dla_p.h @@ -0,0 +1,969 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __DLA__ +#define __DLA__ + +#define DEFAULT_TRIM_THRESHOLD ((size_t)4U * (size_t)1024U) + +#define MSPACES 0 +#define HAVE_MORECORE 1 +#define MORECORE_CONTIGUOUS 1 +#define HAVE_MMAP 0 +#define HAVE_MREMAP 0 +#define DEFAULT_GRANULARITY (4096U) +#define FOOTERS 0 +#define USE_LOCKS 0 +#define INSECURE 1 +#define NO_MALLINFO 0 + +#define LACKS_SYS_TYPES_H +#ifndef LACKS_SYS_TYPES_H +#include /* For size_t */ +#else +#ifndef _SIZE_T_DECLARED +typedef unsigned int size_t; +#define _SIZE_T_DECLARED +#endif +#endif /* LACKS_SYS_TYPES_H */ + +/* The maximum possible size_t value has all bits set */ +#define MAX_SIZE_T (~(size_t)0) + +#ifndef ONLY_MSPACES + #define ONLY_MSPACES 0 +#endif /* ONLY_MSPACES */ + +#ifndef MSPACES + #if ONLY_MSPACES + #define MSPACES 1 + #else /* ONLY_MSPACES */ + #define MSPACES 0 + #endif /* ONLY_MSPACES */ +#endif /* MSPACES */ + +//#ifndef MALLOC_ALIGNMENT +// #define MALLOC_ALIGNMENT ((size_t)8U) +//#endif /* MALLOC_ALIGNMENT */ + +#ifndef FOOTERS + #define FOOTERS 0 +#endif /* FOOTERS */ + +#ifndef ABORT +// #define ABORT abort() +// #define ABORT User::Invariant()// redefined so euser isn't dependant on oe + #define ABORT HEAP_PANIC(ETHeapBadCellAddress) +#endif /* ABORT */ + +#ifndef PROCEED_ON_ERROR + #define PROCEED_ON_ERROR 0 +#endif /* PROCEED_ON_ERROR */ + +#ifndef USE_LOCKS + #define USE_LOCKS 0 +#endif /* USE_LOCKS */ + +#ifndef INSECURE + #define INSECURE 0 +#endif /* INSECURE */ + +#ifndef HAVE_MMAP + #define HAVE_MMAP 1 +#endif /* HAVE_MMAP */ + +#ifndef MMAP_CLEARS + #define MMAP_CLEARS 1 +#endif /* MMAP_CLEARS */ + +#ifndef HAVE_MREMAP + #ifdef linux + #define HAVE_MREMAP 1 + #else /* linux */ + #define HAVE_MREMAP 0 + #endif /* linux */ +#endif /* HAVE_MREMAP */ + +#ifndef MALLOC_FAILURE_ACTION + //#define MALLOC_FAILURE_ACTION errno = ENOMEM; + #define MALLOC_FAILURE_ACTION ; +#endif /* MALLOC_FAILURE_ACTION */ + +#ifndef HAVE_MORECORE + #if ONLY_MSPACES + #define HAVE_MORECORE 1 /*AMOD: has changed */ + #else /* ONLY_MSPACES */ + #define HAVE_MORECORE 1 + #endif /* ONLY_MSPACES */ +#endif /* HAVE_MORECORE */ + +#if !HAVE_MORECORE + #define MORECORE_CONTIGUOUS 0 +#else /* !HAVE_MORECORE */ + #ifndef MORECORE + #define MORECORE DLAdjust + #endif /* MORECORE */ + #ifndef MORECORE_CONTIGUOUS + #define MORECORE_CONTIGUOUS 0 + #endif /* MORECORE_CONTIGUOUS */ +#endif /* !HAVE_MORECORE */ + +#ifndef DEFAULT_GRANULARITY + #if MORECORE_CONTIGUOUS + #define DEFAULT_GRANULARITY 4096 /* 0 means to compute in init_mparams */ + #else /* MORECORE_CONTIGUOUS */ + #define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) + #endif /* MORECORE_CONTIGUOUS */ +#endif /* DEFAULT_GRANULARITY */ + +#ifndef DEFAULT_TRIM_THRESHOLD + #ifndef MORECORE_CANNOT_TRIM + #define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) + #else /* MORECORE_CANNOT_TRIM */ + #define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T + #endif /* MORECORE_CANNOT_TRIM */ +#endif /* DEFAULT_TRIM_THRESHOLD */ + +#ifndef DEFAULT_MMAP_THRESHOLD + #if HAVE_MMAP + #define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) + #else /* HAVE_MMAP */ + #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T + #endif /* HAVE_MMAP */ +#endif /* DEFAULT_MMAP_THRESHOLD */ + +#ifndef USE_BUILTIN_FFS + #define USE_BUILTIN_FFS 0 +#endif /* USE_BUILTIN_FFS */ + +#ifndef USE_DEV_RANDOM + #define USE_DEV_RANDOM 0 +#endif /* USE_DEV_RANDOM */ + +#ifndef NO_MALLINFO + #define NO_MALLINFO 0 +#endif /* NO_MALLINFO */ +#ifndef MALLINFO_FIELD_TYPE + #define MALLINFO_FIELD_TYPE size_t +#endif /* MALLINFO_FIELD_TYPE */ + +/* + mallopt tuning options. SVID/XPG defines four standard parameter + numbers for mallopt, normally defined in malloc.h. None of these + are used in this malloc, so setting them has no effect. But this + malloc does support the following options. +*/ + +#define M_TRIM_THRESHOLD (-1) +#define M_GRANULARITY (-2) +#define M_MMAP_THRESHOLD (-3) + +#if !NO_MALLINFO +/* + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing usage properties and + statistics. It should work on any system that has a + /usr/include/malloc.h defining struct mallinfo. The main + declaration needed is the mallinfo struct that is returned (by-copy) + by mallinfo(). The malloinfo struct contains a bunch of fields that + are not even meaningful in this version of malloc. These fields are + are instead filled by mallinfo() with other numbers that might be of + interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else a compliant version is + declared below. These must be precisely the same for mallinfo() to + work. The original SVID version of this struct, defined on most + systems with mallinfo, declares all fields as ints. But some others + define as unsigned long. If your system defines the fields using a + type of different width than listed here, you MUST #include your + system version and #define HAVE_USR_INCLUDE_MALLOC_H. +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else /* HAVE_USR_INCLUDE_MALLOC_H */ + +struct mallinfo { + MALLINFO_FIELD_TYPE iArena; /* non-mmapped space allocated from system */ + MALLINFO_FIELD_TYPE iOrdblks; /* number of free chunks */ + MALLINFO_FIELD_TYPE iSmblks; /* always 0 */ + MALLINFO_FIELD_TYPE iHblks; /* always 0 */ + MALLINFO_FIELD_TYPE iHblkhd; /* space in mmapped regions */ + MALLINFO_FIELD_TYPE iUsmblks; /* maximum total allocated space */ + MALLINFO_FIELD_TYPE iFsmblks; /* always 0 */ + MALLINFO_FIELD_TYPE iUordblks; /* total allocated space */ + MALLINFO_FIELD_TYPE iFordblks; /* total free space */ + MALLINFO_FIELD_TYPE iKeepcost; /* releasable (via malloc_trim) space */ + MALLINFO_FIELD_TYPE iCellCount;/* Number of chunks allocated*/ +}; + +#endif /* HAVE_USR_INCLUDE_MALLOC_H */ +#endif /* NO_MALLINFO */ + +#if MSPACES + typedef void* mspace; +#endif /* MSPACES */ + +#if 0 + +#include /* for printing in malloc_stats */ + +#ifndef LACKS_ERRNO_H + #include /* for MALLOC_FAILURE_ACTION */ +#endif /* LACKS_ERRNO_H */ + +#if FOOTERS + #include /* for iMagic initialization */ +#endif /* FOOTERS */ + +#ifndef LACKS_STDLIB_H + #include /* for abort() */ +#endif /* LACKS_STDLIB_H */ + +#if !defined(ASSERT) +#define ASSERT(x) __ASSERT_DEBUG(x, HEAP_PANIC(ETHeapBadCellAddress)) +#endif + +#ifndef LACKS_STRING_H + #include /* for memset etc */ +#endif /* LACKS_STRING_H */ + +#if USE_BUILTIN_FFS + #ifndef LACKS_STRINGS_H + #include /* for ffs */ + #endif /* LACKS_STRINGS_H */ +#endif /* USE_BUILTIN_FFS */ + +#if HAVE_MMAP + #ifndef LACKS_SYS_MMAN_H + #include /* for mmap */ + #endif /* LACKS_SYS_MMAN_H */ + #ifndef LACKS_FCNTL_H + #include + #endif /* LACKS_FCNTL_H */ +#endif /* HAVE_MMAP */ + +#if HAVE_MORECORE + #ifndef LACKS_UNISTD_H + #include /* for sbrk */ + extern void* sbrk(size_t); + #else /* LACKS_UNISTD_H */ + #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) + extern void* sbrk(ptrdiff_t); + /*Amod sbrk is not defined in WIN32 need to check in symbian*/ + #endif /* FreeBSD etc */ + #endif /* LACKS_UNISTD_H */ +#endif /* HAVE_MORECORE */ + +#endif + +/*AMOD: For MALLOC_GETPAGESIZE*/ +#if 0 // replaced with GET_PAGE_SIZE() defined in heap.cpp +#ifndef WIN32 + #ifndef MALLOC_GETPAGESIZE + #ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ + #ifndef _SC_PAGE_SIZE + #define _SC_PAGE_SIZE _SC_PAGESIZE + #endif + #endif + #ifdef _SC_PAGE_SIZE + #define MALLOC_GETPAGESIZE sysconf(_SC_PAGE_SIZE) + #else + #if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); + #define MALLOC_GETPAGESIZE getpagesize() + #else + #ifdef WIN32 /* use supplied emulation of getpagesize */ + #define MALLOC_GETPAGESIZE getpagesize() + #else + #ifndef LACKS_SYS_PARAM_H + #include + #endif + #ifdef EXEC_PAGESIZE + #define MALLOC_GETPAGESIZE EXEC_PAGESIZE + #else + #ifdef NBPG + #ifndef CLSIZE + #define MALLOC_GETPAGESIZE NBPG + #else + #define MALLOC_GETPAGESIZE (NBPG * CLSIZE) + #endif + #else + #ifdef NBPC + #define MALLOC_GETPAGESIZE NBPC + #else + #ifdef PAGESIZE + #define MALLOC_GETPAGESIZE PAGESIZE + #else /* just guess */ + #define MALLOC_GETPAGESIZE ((size_t)4096U) + #endif + #endif + #endif + #endif + #endif + #endif + #endif + #endif +#endif +#endif +/*AMOD: For MALLOC_GETPAGESIZE*/ + +/* ------------------- size_t and alignment properties -------------------- */ + +/* The byte and bit size of a size_t */ +#define SIZE_T_SIZE (sizeof(size_t)) +#define SIZE_T_BITSIZE (sizeof(size_t) << 3) + +/* Some constants coerced to size_t */ +/* Annoying but necessary to avoid errors on some plaftorms */ +#define SIZE_T_ZERO ((size_t)0) +#define SIZE_T_ONE ((size_t)1) +#define SIZE_T_TWO ((size_t)2) +#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) +#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) +#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) +#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) + +/* The bit mask value corresponding to MALLOC_ALIGNMENT */ +#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) + +/* True if address a has acceptable alignment */ +//#define IS_ALIGNED(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) +#define IS_ALIGNED(A) (((unsigned int)((A)) & (CHUNK_ALIGN_MASK)) == 0) + +/* the number of bytes to offset an address to align it */ +#define ALIGN_OFFSET(A)\ + ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ + ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) + +/* -------------------------- MMAP preliminaries ------------------------- */ + +/* + If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and + checks to fail so compiler optimizer can delete code rather than + using so many "#if"s. +*/ + + +/* MORECORE and MMAP must return MFAIL on failure */ +#define MFAIL ((void*)(MAX_SIZE_T)) +#define CMFAIL ((TUint8*)(MFAIL)) /* defined for convenience */ + +#if !HAVE_MMAP + #define IS_MMAPPED_BIT (SIZE_T_ZERO) + #define USE_MMAP_BIT (SIZE_T_ZERO) + #define CALL_MMAP(s) MFAIL + #define CALL_MUNMAP(a, s) (-1) + #define DIRECT_MMAP(s) MFAIL +#else /* !HAVE_MMAP */ + #define IS_MMAPPED_BIT (SIZE_T_ONE) + #define USE_MMAP_BIT (SIZE_T_ONE) + #ifndef WIN32 + #define CALL_MUNMAP(a, s) DLUMMAP((a),(s)) /*munmap((a), (s))*/ + #define MMAP_PROT (PROT_READ|PROT_WRITE) + #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) + #define MAP_ANONYMOUS MAP_ANON + #endif /* MAP_ANON */ + #ifdef MAP_ANONYMOUS + #define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) + #define CALL_MMAP(s) mmap(0, (s), MMAP_PROT, (int)MMAP_FLAGS, -1, 0) + #else /* MAP_ANONYMOUS */ + /* + Nearly all versions of mmap support MAP_ANONYMOUS, so the following + is unlikely to be needed, but is supplied just in case. + */ + #define MMAP_FLAGS (MAP_PRIVATE) + //static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ + #define CALL_MMAP(s) DLMMAP(s) + /*#define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ + (dev_zero_fd = open("/dev/zero", O_RDWR), \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ + mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) + */ + #define CALL_REMAP(a, s, d) DLREMAP((a),(s),(d)) + #endif /* MAP_ANONYMOUS */ + #define DIRECT_MMAP(s) CALL_MMAP(s) + #else /* WIN32 */ + #define CALL_MMAP(s) win32mmap(s) + #define CALL_MUNMAP(a, s) win32munmap((a), (s)) + #define DIRECT_MMAP(s) win32direct_mmap(s) + #endif /* WIN32 */ +#endif /* HAVE_MMAP */ + +#if HAVE_MMAP && HAVE_MREMAP + #define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) +#else /* HAVE_MMAP && HAVE_MREMAP */ + #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL +#endif /* HAVE_MMAP && HAVE_MREMAP */ + +#if HAVE_MORECORE + #define CALL_MORECORE(S) SetBrk(S) +#else /* HAVE_MORECORE */ + #define CALL_MORECORE(S) MFAIL +#endif /* HAVE_MORECORE */ + +/* mstate bit set if continguous morecore disabled or failed */ +#define USE_NONCONTIGUOUS_BIT (4U) + +/* segment bit set in create_mspace_with_base */ +#define EXTERN_BIT (8U) + + +#if USE_LOCKS +/* + When locks are defined, there are up to two global locks: + * If HAVE_MORECORE, iMorecoreMutex protects sequences of calls to + MORECORE. In many cases sys_alloc requires two calls, that should + not be interleaved with calls by other threads. This does not + protect against direct calls to MORECORE by other threads not + using this lock, so there is still code to cope the best we can on + interference. + * iMagicInitMutex ensures that mparams.iMagic and other + unique mparams values are initialized only once. +*/ + #ifndef WIN32 + /* By default use posix locks */ + #include + #define MLOCK_T pthread_mutex_t + #define INITIAL_LOCK(l) pthread_mutex_init(l, NULL) + #define ACQUIRE_LOCK(l) pthread_mutex_lock(l) + #define RELEASE_LOCK(l) pthread_mutex_unlock(l) + + #if HAVE_MORECORE + //static MLOCK_T iMorecoreMutex = PTHREAD_MUTEX_INITIALIZER; + #endif /* HAVE_MORECORE */ + //static MLOCK_T iMagicInitMutex = PTHREAD_MUTEX_INITIALIZER; + #else /* WIN32 */ + #define MLOCK_T long + #define INITIAL_LOCK(l) *(l)=0 + #define ACQUIRE_LOCK(l) win32_acquire_lock(l) + #define RELEASE_LOCK(l) win32_release_lock(l) + #if HAVE_MORECORE + static MLOCK_T iMorecoreMutex; + #endif /* HAVE_MORECORE */ + static MLOCK_T iMagicInitMutex; + #endif /* WIN32 */ + #define USE_LOCK_BIT (2U) +#else /* USE_LOCKS */ + #define USE_LOCK_BIT (0U) + #define INITIAL_LOCK(l) +#endif /* USE_LOCKS */ + +#if USE_LOCKS && HAVE_MORECORE + #define ACQUIRE_MORECORE_LOCK(M) ACQUIRE_LOCK((M->iMorecoreMutex)/*&iMorecoreMutex*/); + #define RELEASE_MORECORE_LOCK(M) RELEASE_LOCK((M->iMorecoreMutex)/*&iMorecoreMutex*/); +#else /* USE_LOCKS && HAVE_MORECORE */ + #define ACQUIRE_MORECORE_LOCK(M) + #define RELEASE_MORECORE_LOCK(M) +#endif /* USE_LOCKS && HAVE_MORECORE */ + +#if USE_LOCKS + /*Currently not suporting this*/ + #define ACQUIRE_MAGIC_INIT_LOCK(M) ACQUIRE_LOCK(((M)->iMagicInitMutex)); + //AMOD: changed #define ACQUIRE_MAGIC_INIT_LOCK() + //#define RELEASE_MAGIC_INIT_LOCK() + #define RELEASE_MAGIC_INIT_LOCK(M) RELEASE_LOCK(((M)->iMagicInitMutex)); +#else /* USE_LOCKS */ + #define ACQUIRE_MAGIC_INIT_LOCK(M) + #define RELEASE_MAGIC_INIT_LOCK(M) +#endif /* USE_LOCKS */ + +/*CHUNK representation*/ +struct malloc_chunk { + size_t iPrevFoot; /* Size of previous chunk (if free). */ + size_t iHead; /* Size and inuse bits. */ + struct malloc_chunk* iFd; /* double links -- used only if free. */ + struct malloc_chunk* iBk; +}; + +typedef struct malloc_chunk mchunk; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ +typedef unsigned int bindex_t; /* Described below */ +typedef unsigned int binmap_t; /* Described below */ +typedef unsigned int flag_t; /* The type of various bit flag sets */ + + +/* ------------------- Chunks sizes and alignments ----------------------- */ +#define MCHUNK_SIZE (sizeof(mchunk)) + +//#if FOOTERS +// #define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +//#else /* FOOTERS */ +// #define CHUNK_OVERHEAD (SIZE_T_SIZE) +//#endif /* FOOTERS */ + +/* MMapped chunks need a second word of overhead ... */ +#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) +/* ... and additional padding for fake next-chunk at foot */ +#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) + +/* The smallest size we can malloc is an aligned minimal chunk */ +#define MIN_CHUNK_SIZE ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* conversion from malloc headers to user pointers, and back */ +#define CHUNK2MEM(p) ((void*)((TUint8*)(p) + TWO_SIZE_T_SIZES)) +#define MEM2CHUNK(mem) ((mchunkptr)((TUint8*)(mem) - TWO_SIZE_T_SIZES)) +/* chunk associated with aligned address A */ +#define ALIGN_AS_CHUNK(A) (mchunkptr)((A) + ALIGN_OFFSET(CHUNK2MEM(A))) + +/* Bounds on request (not chunk) sizes. */ +#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) +#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) + +/* pad request bytes into a usable size */ +#define PAD_REQUEST(req) (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) + +/* pad request, checking for minimum (but not maximum) */ +#define REQUEST2SIZE(req) (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : PAD_REQUEST(req)) + +/* ------------------ Operations on iHead and foot fields ----------------- */ + +/* + The iHead field of a chunk is or'ed with PINUSE_BIT when previous + adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in + use. If the chunk was obtained with mmap, the iPrevFoot field has + IS_MMAPPED_BIT set, otherwise holding the offset of the base of the + mmapped region to the base of the chunk. +*/ +#define PINUSE_BIT (SIZE_T_ONE) +#define CINUSE_BIT (SIZE_T_TWO) +#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) + +/* Head value for fenceposts */ +#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) + +/* extraction of fields from iHead words */ +#define CINUSE(p) ((p)->iHead & CINUSE_BIT) +#define PINUSE(p) ((p)->iHead & PINUSE_BIT) +#define CHUNKSIZE(p) ((p)->iHead & ~(INUSE_BITS)) + +#define CLEAR_PINUSE(p) ((p)->iHead &= ~PINUSE_BIT) +#define CLEAR_CINUSE(p) ((p)->iHead &= ~CINUSE_BIT) + +/* Treat space at ptr +/- offset as a chunk */ +#define CHUNK_PLUS_OFFSET(p, s) ((mchunkptr)(((TUint8*)(p)) + (s))) +#define CHUNK_MINUS_OFFSET(p, s) ((mchunkptr)(((TUint8*)(p)) - (s))) + +/* Ptr to next or previous physical malloc_chunk. */ +#define NEXT_CHUNK(p) ((mchunkptr)( ((TUint8*)(p)) + ((p)->iHead & ~INUSE_BITS))) +#define PREV_CHUNK(p) ((mchunkptr)( ((TUint8*)(p)) - ((p)->iPrevFoot) )) + +/* extract next chunk's PINUSE bit */ +#define NEXT_PINUSE(p) ((NEXT_CHUNK(p)->iHead) & PINUSE_BIT) + +/* Get/set size at footer */ +#define GET_FOOT(p, s) (((mchunkptr)((TUint8*)(p) + (s)))->iPrevFoot) +#define SET_FOOT(p, s) (((mchunkptr)((TUint8*)(p) + (s)))->iPrevFoot = (s)) + +/* Set size, PINUSE bit, and foot */ +#define SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, s) ((p)->iHead = (s|PINUSE_BIT), SET_FOOT(p, s)) + +/* Set size, PINUSE bit, foot, and clear next PINUSE */ +#define SET_FREE_WITH_PINUSE(p, s, n) (CLEAR_PINUSE(n), SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, s)) + +#define IS_MMAPPED(p) (!((p)->iHead & PINUSE_BIT) && ((p)->iPrevFoot & IS_MMAPPED_BIT)) + +/* Get the internal overhead associated with chunk p */ +#define OVERHEAD_FOR(p) (IS_MMAPPED(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) + +/* Return true if malloced space is not necessarily cleared */ +#if MMAP_CLEARS + #define CALLOC_MUST_CLEAR(p) (!IS_MMAPPED(p)) +#else /* MMAP_CLEARS */ + #define CALLOC_MUST_CLEAR(p) (1) +#endif /* MMAP_CLEARS */ + +/* ---------------------- Overlaid data structures ----------------------- */ +struct malloc_tree_chunk { + /* The first four fields must be compatible with malloc_chunk */ + size_t iPrevFoot; + size_t iHead; + struct malloc_tree_chunk* iFd; + struct malloc_tree_chunk* iBk; + + struct malloc_tree_chunk* iChild[2]; + struct malloc_tree_chunk* iParent; + bindex_t iIndex; +}; + +typedef struct malloc_tree_chunk tchunk; +typedef struct malloc_tree_chunk* tchunkptr; +typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ + +/* A little helper macro for trees */ +#define LEFTMOST_CHILD(t) ((t)->iChild[0] != 0? (t)->iChild[0] : (t)->iChild[1]) +/*Segment structur*/ +//struct malloc_segment { +// TUint8* iBase; /* base address */ +// size_t iSize; /* allocated size */ +//}; + +#define IS_MMAPPED_SEGMENT(S) ((S)->iSflags & IS_MMAPPED_BIT) +#define IS_EXTERN_SEGMENT(S) ((S)->iSflags & EXTERN_BIT) + +typedef struct malloc_segment msegment; +typedef struct malloc_segment* msegmentptr; + +/*Malloc State data structur*/ + +//#define NSMALLBINS (32U) +//#define NTREEBINS (32U) +#define SMALLBIN_SHIFT (3U) +#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) +#define TREEBIN_SHIFT (8U) +#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) +#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) +#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) + +/*struct malloc_state { + binmap_t iSmallMap; + binmap_t iTreeMap; + size_t iDvSize; + size_t iTopSize; + mchunkptr iDv; + mchunkptr iTop; + size_t iTrimCheck; + mchunkptr iSmallBins[(NSMALLBINS+1)*2]; + tbinptr iTreeBins[NTREEBINS]; + msegment iSeg; + };*/ +/* +struct malloc_state { + binmap_t iSmallMap; + binmap_t iTreeMap; + size_t iDvSize; + size_t iTopSize; + TUint8* iLeastAddr; + mchunkptr iDv; + mchunkptr iTop; + size_t iTrimCheck; + size_t iMagic; + mchunkptr iSmallBins[(NSMALLBINS+1)*2]; + tbinptr iTreeBins[NTREEBINS]; + size_t iFootprint; + size_t iMaxFootprint; + flag_t iMflags; +#if USE_LOCKS + MLOCK_T iMutex; + MLOCK_T iMagicInitMutex; + MLOCK_T iMorecoreMutex; +#endif + msegment iSeg; +}; +*/ +typedef struct malloc_state* mstate; + +/* ------------- Global malloc_state and malloc_params ------------------- */ + +/* + malloc_params holds global properties, including those that can be + dynamically set using mallopt. There is a single instance, mparams, + initialized in init_mparams. +*/ + +struct malloc_params { + size_t iMagic; + size_t iPageSize; + size_t iGranularity; + size_t iMmapThreshold; + size_t iTrimThreshold; + flag_t iDefaultMflags; +#if USE_LOCKS + MLOCK_T iMagicInitMutex; +#endif /* USE_LOCKS */ +}; + +/* The global malloc_state used for all non-"mspace" calls */ +/*AMOD: Need to check this as this will be the member of the class*/ + +//static struct malloc_state _gm_; +//#define GM (&_gm_) + +//#define IS_GLOBAL(M) ((M) == &_gm_) +/*AMOD: has changed*/ +#define IS_GLOBAL(M) ((M) == GM) +#define IS_INITIALIZED(M) ((M)->iTop != 0) + +/* -------------------------- system alloc setup ------------------------- */ + +/* Operations on iMflags */ + +#define USE_LOCK(M) ((M)->iMflags & USE_LOCK_BIT) +#define ENABLE_LOCK(M) ((M)->iMflags |= USE_LOCK_BIT) +#define DISABLE_LOCK(M) ((M)->iMflags &= ~USE_LOCK_BIT) + +#define USE_MMAP(M) ((M)->iMflags & USE_MMAP_BIT) +#define ENABLE_MMAP(M) ((M)->iMflags |= USE_MMAP_BIT) +#define DISABLE_MMAP(M) ((M)->iMflags &= ~USE_MMAP_BIT) + +#define USE_NONCONTIGUOUS(M) ((M)->iMflags & USE_NONCONTIGUOUS_BIT) +#define DISABLE_CONTIGUOUS(M) ((M)->iMflags |= USE_NONCONTIGUOUS_BIT) + +#define SET_LOCK(M,L) ((M)->iMflags = (L)? ((M)->iMflags | USE_LOCK_BIT) : ((M)->iMflags & ~USE_LOCK_BIT)) + +/* page-align a size */ +#define PAGE_ALIGN(S) (((S) + (mparams.iPageSize)) & ~(mparams.iPageSize - SIZE_T_ONE)) + +/* iGranularity-align a size */ +#define GRANULARITY_ALIGN(S) (((S) + (mparams.iGranularity)) & ~(mparams.iGranularity - SIZE_T_ONE)) + +#define IS_PAGE_ALIGNED(S) (((size_t)(S) & (mparams.iPageSize - SIZE_T_ONE)) == 0) +#define IS_GRANULARITY_ALIGNED(S) (((size_t)(S) & (mparams.iGranularity - SIZE_T_ONE)) == 0) + +/* True if segment S holds address A */ +#define SEGMENT_HOLDS(S, A) ((TUint8*)(A) >= S->iBase && (TUint8*)(A) < S->iBase + S->iSize) + +#ifndef MORECORE_CANNOT_TRIM + #define SHOULD_TRIM(M,s) ((s) > (M)->iTrimCheck) +#else /* MORECORE_CANNOT_TRIM */ + #define SHOULD_TRIM(M,s) (0) +#endif /* MORECORE_CANNOT_TRIM */ + +/* + TOP_FOOT_SIZE is padding at the end of a segment, including space + that may be needed to place segment records and fenceposts when new + noncontiguous segments are added. +*/ +#define TOP_FOOT_SIZE (ALIGN_OFFSET(CHUNK2MEM(0))+PAD_REQUEST(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) + +#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) +/* ------------------------------- Hooks -------------------------------- */ + +/* + PREACTION should be defined to return 0 on success, and nonzero on + failure. If you are not using locking, you can redefine these to do + anything you like. +*/ + +#if USE_LOCKS + /* Ensure locks are initialized */ + #define GLOBALLY_INITIALIZE() (mparams.iPageSize == 0 && init_mparams()) + #define PREACTION(M) (USE_LOCK((M))?(ACQUIRE_LOCK((M)->iMutex),0):0) /*Action to take like lock before alloc*/ + #define POSTACTION(M) { if (USE_LOCK(M)) RELEASE_LOCK((M)->iMutex); } + +#else /* USE_LOCKS */ + #ifndef PREACTION + #define PREACTION(M) (0) + #endif /* PREACTION */ + #ifndef POSTACTION + #define POSTACTION(M) + #endif /* POSTACTION */ +#endif /* USE_LOCKS */ + +/* + CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. + USAGE_ERROR_ACTION is triggered on detected bad frees and + reallocs. The argument p is an address that might have triggered the + fault. It is ignored by the two predefined actions, but might be + useful in custom actions that try to help diagnose errors. +*/ + +#if PROCEED_ON_ERROR + /* A count of the number of corruption errors causing resets */ + int malloc_corruption_error_count; + /* default corruption action */ + static void ResetOnError(mstate m); + #define CORRUPTION_ERROR_ACTION(m) ResetOnError(m) + #define USAGE_ERROR_ACTION(m, p) +#else /* PROCEED_ON_ERROR */ + #ifndef CORRUPTION_ERROR_ACTION + #define CORRUPTION_ERROR_ACTION(m) ABORT + #endif /* CORRUPTION_ERROR_ACTION */ + #ifndef USAGE_ERROR_ACTION + #define USAGE_ERROR_ACTION(m,p) ABORT + #endif /* USAGE_ERROR_ACTION */ +#endif /* PROCEED_ON_ERROR */ + + +#ifdef _DEBUG + #define CHECK_FREE_CHUNK(M,P) DoCheckFreeChunk(M,P) + #define CHECK_INUSE_CHUNK(M,P) DoCheckInuseChunk(M,P) + #define CHECK_TOP_CHUNK(M,P) DoCheckTopChunk(M,P) + #define CHECK_MALLOCED_CHUNK(M,P,N) DoCheckMallocedChunk(M,P,N) + #define CHECK_MMAPPED_CHUNK(M,P) DoCheckMmappedChunk(M,P) + #define CHECK_MALLOC_STATE(M) DoCheckMallocState(M) +#else /* DEBUG */ + #define CHECK_FREE_CHUNK(M,P) + #define CHECK_INUSE_CHUNK(M,P) + #define CHECK_MALLOCED_CHUNK(M,P,N) + #define CHECK_MMAPPED_CHUNK(M,P) + #define CHECK_MALLOC_STATE(M) + #define CHECK_TOP_CHUNK(M,P) +#endif /* DEBUG */ + +/* ---------------------------- Indexing Bins ---------------------------- */ + +#define IS_SMALL(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) +#define SMALL_INDEX(s) ((s) >> SMALLBIN_SHIFT) +#define SMALL_INDEX2SIZE(i) ((i) << SMALLBIN_SHIFT) +#define MIN_SMALL_INDEX (SMALL_INDEX(MIN_CHUNK_SIZE)) + +/* addressing by index. See above about smallbin repositioning */ +#define SMALLBIN_AT(M, i) ((sbinptr)((TUint8*)&((M)->iSmallBins[(i)<<1]))) +#define TREEBIN_AT(M,i) (&((M)->iTreeBins[i])) + + +/* Bit representing maximum resolved size in a treebin at i */ +#define BIT_FOR_TREE_INDEX(i) (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) + +/* Shift placing maximum resolved bit in a treebin at i as sign bit */ +#define LEFTSHIFT_FOR_TREE_INDEX(i) ((i == NTREEBINS-1)? 0 : ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) + +/* The size of the smallest chunk held in bin with index i */ +#define MINSIZE_FOR_TREE_INDEX(i) ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) + + +/* ------------------------ Operations on bin maps ----------------------- */ +/* bit corresponding to given index */ +#define IDX2BIT(i) ((binmap_t)(1) << (i)) +/* Mark/Clear bits with given index */ +#define MARK_SMALLMAP(M,i) ((M)->iSmallMap |= IDX2BIT(i)) +#define CLEAR_SMALLMAP(M,i) ((M)->iSmallMap &= ~IDX2BIT(i)) +#define SMALLMAP_IS_MARKED(M,i) ((M)->iSmallMap & IDX2BIT(i)) +#define MARK_TREEMAP(M,i) ((M)->iTreeMap |= IDX2BIT(i)) +#define CLEAR_TREEMAP(M,i) ((M)->iTreeMap &= ~IDX2BIT(i)) +#define TREEMAP_IS_MARKED(M,i) ((M)->iTreeMap & IDX2BIT(i)) + + /* isolate the least set bit of a bitmap */ +#define LEAST_BIT(x) ((x) & -(x)) + +/* mask with all bits to left of least bit of x on */ +#define LEFT_BITS(x) ((x<<1) | -(x<<1)) + +/* mask with all bits to left of or equal to least bit of x on */ +#define SAME_OR_LEFT_BITS(x) ((x) | -(x)) + +#if !INSECURE + /* Check if address a is at least as high as any from MORECORE or MMAP */ + #define OK_ADDRESS(M, a) ((TUint8*)(a) >= (M)->iLeastAddr) + /* Check if address of next chunk n is higher than base chunk p */ + #define OK_NEXT(p, n) ((TUint8*)(p) < (TUint8*)(n)) + /* Check if p has its CINUSE bit on */ + #define OK_CINUSE(p) CINUSE(p) + /* Check if p has its PINUSE bit on */ + #define OK_PINUSE(p) PINUSE(p) +#else /* !INSECURE */ + #define OK_ADDRESS(M, a) (1) + #define OK_NEXT(b, n) (1) + #define OK_CINUSE(p) (1) + #define OK_PINUSE(p) (1) +#endif /* !INSECURE */ + +#if (FOOTERS && !INSECURE) + /* Check if (alleged) mstate m has expected iMagic field */ + #define OK_MAGIC(M) ((M)->iMagic == mparams.iMagic) +#else /* (FOOTERS && !INSECURE) */ + #define OK_MAGIC(M) (1) +#endif /* (FOOTERS && !INSECURE) */ + +/* In gcc, use __builtin_expect to minimize impact of checks */ +#if !INSECURE + #if defined(__GNUC__) && __GNUC__ >= 3 + #define RTCHECK(e) __builtin_expect(e, 1) + #else /* GNUC */ + #define RTCHECK(e) (e) + #endif /* GNUC */ + +#else /* !INSECURE */ + #define RTCHECK(e) (1) +#endif /* !INSECURE */ +/* macros to set up inuse chunks with or without footers */ +#if !FOOTERS + #define MARK_INUSE_FOOT(M,p,s) + /* Set CINUSE bit and PINUSE bit of next chunk */ + #define SET_INUSE(M,p,s) ((p)->iHead = (((p)->iHead & PINUSE_BIT)|s|CINUSE_BIT),((mchunkptr)(((TUint8*)(p)) + (s)))->iHead |= PINUSE_BIT) + /* Set CINUSE and PINUSE of this chunk and PINUSE of next chunk */ + #define SET_INUSE_AND_PINUSE(M,p,s) ((p)->iHead = (s|PINUSE_BIT|CINUSE_BIT),((mchunkptr)(((TUint8*)(p)) + (s)))->iHead |= PINUSE_BIT) + /* Set size, CINUSE and PINUSE bit of this chunk */ + #define SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(M, p, s) ((p)->iHead = (s|PINUSE_BIT|CINUSE_BIT)) +#else /* FOOTERS */ + /* Set foot of inuse chunk to be xor of mstate and seed */ + #define MARK_INUSE_FOOT(M,p,s) (((mchunkptr)((TUint8*)(p) + (s)))->iPrevFoot = ((size_t)(M) ^ mparams.iMagic)) + #define GET_MSTATE_FOR(p) ((mstate)(((mchunkptr)((TUint8*)(p)+(CHUNKSIZE(p))))->iPrevFoot ^ mparams.iMagic)) + #define SET_INUSE(M,p,s)\ + ((p)->iHead = (((p)->iHead & PINUSE_BIT)|s|CINUSE_BIT),\ + (((mchunkptr)(((TUint8*)(p)) + (s)))->iHead |= PINUSE_BIT), \ + MARK_INUSE_FOOT(M,p,s)) + #define SET_INUSE_AND_PINUSE(M,p,s)\ + ((p)->iHead = (s|PINUSE_BIT|CINUSE_BIT),\ + (((mchunkptr)(((TUint8*)(p)) + (s)))->iHead |= PINUSE_BIT),\ + MARK_INUSE_FOOT(M,p,s)) + #define SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(M, p, s)\ + ((p)->iHead = (s|PINUSE_BIT|CINUSE_BIT),\ + MARK_INUSE_FOOT(M, p, s)) +#endif /* !FOOTERS */ + + +#if ONLY_MSPACES +#define INTERNAL_MALLOC(m, b) mspace_malloc(m, b) +#define INTERNAL_FREE(m, mem) mspace_free(m,mem); +#else /* ONLY_MSPACES */ + #if MSPACES + #define INTERNAL_MALLOC(m, b) (m == GM)? dlmalloc(b) : mspace_malloc(m, b) + #define INTERNAL_FREE(m, mem) if (m == GM) dlfree(mem); else mspace_free(m,mem); + #else /* MSPACES */ + #define INTERNAL_MALLOC(m, b) dlmalloc(b) + #define INTERNAL_FREE(m, mem) dlfree(mem) + #endif /* MSPACES */ +#endif /* ONLY_MSPACES */ + + #ifndef NDEBUG + #define CHECKING 1 + #endif +// #define HYSTERESIS 4 + #define HYSTERESIS 1 + #define HYSTERESIS_BYTES (2*PAGESIZE) + #define HYSTERESIS_GROW (HYSTERESIS*PAGESIZE) + + #if CHECKING + #define CHECK(x) x + #else + #undef ASSERT + #define ASSERT(x) (void)0 + #define CHECK(x) (void)0 + #endif + +#endif/*__DLA__*/ diff --git a/src/corelib/arch/symbian/heap_hybrid.cpp b/src/corelib/arch/symbian/heap_hybrid.cpp new file mode 100644 index 0000000000..6e2ef21e93 --- /dev/null +++ b/src/corelib/arch/symbian/heap_hybrid.cpp @@ -0,0 +1,3346 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt_hybridheap_symbian_p.h" + +#ifdef QT_USE_NEW_SYMBIAN_ALLOCATOR + +// if non zero this causes the iSlabs to be configured only when the chunk size exceeds this level +#define DELAYED_SLAB_THRESHOLD (64*1024) // 64KB seems about right based on trace data +#define SLAB_CONFIG 0x3fff // Use all slab sizes 4,8..56 bytes. This is more efficient for large heaps as Qt tends to have + +#ifdef _DEBUG +#define __SIMULATE_ALLOC_FAIL(s) if (CheckForSimulatedAllocFail()) {s} +#define __ALLOC_DEBUG_HEADER(s) (s += EDebugHdrSize) +#define __SET_DEBUG_DATA(p,n,c) (((SDebugCell*)(p))->nestingLevel = (n), ((SDebugCell*)(p))->allocCount = (c)) +#define __GET_USER_DATA_BFR(p) ((p!=0) ? (TUint8*)(p) + EDebugHdrSize : NULL) +#define __GET_DEBUG_DATA_BFR(p) ((p!=0) ? (TUint8*)(p) - EDebugHdrSize : NULL) +#define __ZAP_CELL(p) memset( (TUint8*)p, 0xde, (AllocLen(__GET_USER_DATA_BFR(p))+EDebugHdrSize)) +#define __DEBUG_SAVE(p) TInt dbgNestLevel = ((SDebugCell*)p)->nestingLevel +#define __DEBUG_RESTORE(p) if (p) {((SDebugCell*)p)->nestingLevel = dbgNestLevel;} +#define __DEBUG_HDR_SIZE EDebugHdrSize +#define __REMOVE_DBG_HDR(n) (n*EDebugHdrSize) +#define __GET_AVAIL_BLOCK_SIZE(s) ( (sallocCount = (c);} +#define __INIT_COUNTERS(i) iCellCount=i,iTotalAllocSize=i +#define __INCREMENT_COUNTERS(p) iCellCount++, iTotalAllocSize += AllocLen(p) +#define __DECREMENT_COUNTERS(p) iCellCount--, iTotalAllocSize -= AllocLen(p) +#define __UPDATE_TOTAL_ALLOC(p,s) iTotalAllocSize += (AllocLen(__GET_USER_DATA_BFR(p)) - s) + +#else +#define __SIMULATE_ALLOC_FAIL(s) +#define __ALLOC_DEBUG_HEADER(s) +#define __SET_DEBUG_DATA(p,n,c) +#define __GET_USER_DATA_BFR(p) (p) +#define __GET_DEBUG_DATA_BFR(p) (p) +#define __ZAP_CELL(p) +#define __DEBUG_SAVE(p) +#define __DEBUG_RESTORE(p) +#define __DEBUG_HDR_SIZE 0 +#define __REMOVE_DBG_HDR(n) 0 +#define __GET_AVAIL_BLOCK_SIZE(s) (s) +#define __UPDATE_ALLOC_COUNT(o,n,c) +#define __INIT_COUNTERS(i) iCellCount=i,iTotalAllocSize=i +#define __INCREMENT_COUNTERS(p) +#define __DECREMENT_COUNTERS(p) +#define __UPDATE_TOTAL_ALLOC(p,s) + +#endif + + +#define MEMORY_MONITORED (iFlags & EMonitorMemory) +#define GM (&iGlobalMallocState) +#define IS_FIXED_HEAP (iFlags & EFixedSize) +#define __INIT_COUNTERS(i) iCellCount=i,iTotalAllocSize=i +#define __POWER_OF_2(x) (!((x)&((x)-1))) + +#define __DL_BFR_CHECK(M,P) \ + if ( MEMORY_MONITORED ) \ + if ( !IS_ALIGNED(P) || ((TUint8*)(P)iSeg.iBase) || ((TUint8*)(P)>(M->iSeg.iBase+M->iSeg.iSize))) \ + BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)0), HEAP_PANIC(ETHeapBadCellAddress); \ + else DoCheckInuseChunk(M, MEM2CHUNK(P)) + +#ifndef __KERNEL_MODE__ + +#define __SLAB_BFR_CHECK(S,P,B) \ + if ( MEMORY_MONITORED ) \ + if ( ((TUint32)P & 0x3) || ((TUint8*)P(TUint8*)this)) \ + BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)S), HEAP_PANIC(ETHeapBadCellAddress); \ + else DoCheckSlab(S, EPartialFullSlab, P), BuildPartialSlabBitmap(B,S,P) +#define __PAGE_BFR_CHECK(P) \ + if ( MEMORY_MONITORED ) \ + if ( ((TUint32)P & ((1 << iPageSize)-1)) || ((TUint8*)P(TUint8*)this)) \ + BTraceContext12(BTrace::EHeap, BTrace::EHeapCorruption, (TUint32)this, (TUint32)P, (TUint32)0), HEAP_PANIC(ETHeapBadCellAddress) + +#endif + +#ifdef _MSC_VER +// This is required while we are still using VC6 to compile, so as to avoid warnings that cannot be fixed +// without having to edit the original Doug Lea source. The 4146 warnings are due to the original code having +// a liking for negating unsigned numbers and the 4127 warnings are due to the original code using the RTCHECK +// macro with values that are always defined as 1. It is better to turn these warnings off than to introduce +// diffs between the original Doug Lea implementation and our adaptation of it +#pragma warning( disable : 4146 ) /* unary minus operator applied to unsigned type, result still unsigned */ +#pragma warning( disable : 4127 ) /* conditional expression is constant */ +#endif // _MSC_VER + + +/** +@SYMPatchable +@publishedPartner +@released + +Defines the minimum cell size of a heap. + +The constant can be changed at ROM build time using patchdata OBY keyword. + +@deprecated Patching this constant no longer has any effect. +*/ +#ifdef __X86GCC__ // For X86GCC we don't use the proper data import attribute +#undef IMPORT_D // since the constants are not really imported. GCC doesn't +#define IMPORT_D // allow imports from self. +#endif +IMPORT_D extern const TInt KHeapMinCellSize; + +/** +@SYMPatchable +@publishedPartner +@released + +This constant defines the ratio that determines the amount of hysteresis between heap growing and heap +shrinking. +It is a 32-bit fixed point number where the radix point is defined to be +between bits 7 and 8 (where the LSB is bit 0) i.e. using standard notation, a Q8 or a fx24.8 +fixed point number. For example, for a ratio of 2.0, set KHeapShrinkHysRatio=0x200. + +The heap shrinking hysteresis value is calculated to be: +@code +KHeapShrinkHysRatio*(iGrowBy>>8) +@endcode +where iGrowBy is a page aligned value set by the argument, aGrowBy, to the RHeap constructor. +The default hysteresis value is iGrowBy bytes i.e. KHeapShrinkHysRatio=2.0. + +Memory usage may be improved by reducing the heap shrinking hysteresis +by setting 1.0 < KHeapShrinkHysRatio < 2.0. Heap shrinking hysteresis is disabled/removed +when KHeapShrinkHysRatio <= 1.0. + +The constant can be changed at ROM build time using patchdata OBY keyword. +*/ +IMPORT_D extern const TInt KHeapShrinkHysRatio; + +UEXPORT_C TInt RHeap::AllocLen(const TAny* aCell) const +{ + const MAllocator* m = this; + return m->AllocLen(aCell); +} + +UEXPORT_C TAny* RHeap::Alloc(TInt aSize) +{ + const MAllocator* m = this; + return ((MAllocator*)m)->Alloc(aSize); +} + +UEXPORT_C void RHeap::Free(TAny* aCell) +{ + const MAllocator* m = this; + ((MAllocator*)m)->Free(aCell); +} + +UEXPORT_C TAny* RHeap::ReAlloc(TAny* aCell, TInt aSize, TInt aMode) +{ + const MAllocator* m = this; + return ((MAllocator*)m)->ReAlloc(aCell, aSize, aMode); +} + +UEXPORT_C TInt RHeap::DebugFunction(TInt aFunc, TAny* a1, TAny* a2) +{ + const MAllocator* m = this; + return ((MAllocator*)m)->DebugFunction(aFunc, a1, a2); +} + +UEXPORT_C TInt RHeap::Extension_(TUint aExtensionId, TAny*& a0, TAny* a1) +{ + const MAllocator* m = this; + return ((MAllocator*)m)->Extension_(aExtensionId, a0, a1); +} + +#ifndef __KERNEL_MODE__ + +EXPORT_C TInt RHeap::AllocSize(TInt& aTotalAllocSize) const +{ + const MAllocator* m = this; + return m->AllocSize(aTotalAllocSize); +} + +EXPORT_C TInt RHeap::Available(TInt& aBiggestBlock) const +{ + const MAllocator* m = this; + return m->Available(aBiggestBlock); +} + +EXPORT_C void RHeap::Reset() +{ + const MAllocator* m = this; + ((MAllocator*)m)->Reset(); +} + +EXPORT_C TInt RHeap::Compress() +{ + const MAllocator* m = this; + return ((MAllocator*)m)->Compress(); +} +#endif + +RHybridHeap::RHybridHeap() + { + // This initialisation cannot be done in RHeap() for compatibility reasons + iMaxLength = iChunkHandle = iNestingLevel = 0; + iTop = NULL; + iFailType = ENone; + iTestData = NULL; + } + +void RHybridHeap::operator delete(TAny*, TAny*) +/** +Called if constructor issued by operator new(TUint aSize, TAny* aBase) throws exception. +This is dummy as corresponding new operator does not allocate memory. +*/ +{} + + +#ifndef __KERNEL_MODE__ +void RHybridHeap::Lock() const + /** + @internalComponent +*/ + {((RFastLock&)iLock).Wait();} + + +void RHybridHeap::Unlock() const + /** + @internalComponent +*/ + {((RFastLock&)iLock).Signal();} + + +TInt RHybridHeap::ChunkHandle() const + /** + @internalComponent +*/ +{ + return iChunkHandle; +} + +#else +// +// This method is implemented in kheap.cpp +// +//void RHybridHeap::Lock() const + /** + @internalComponent +*/ +// {;} + + + +// +// This method is implemented in kheap.cpp +// +//void RHybridHeap::Unlock() const + /** + @internalComponent +*/ +// {;} + + +TInt RHybridHeap::ChunkHandle() const + /** + @internalComponent +*/ +{ + return 0; +} +#endif + +RHybridHeap::RHybridHeap(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread, TBool aDLOnly, TBool aUseAdjust) +/** +Constructor for a non fixed heap. Unlike the fixed heap, this heap is quite flexible in terms of its minimum and +maximum lengths and in that it can use the hybrid allocator if all of its requirements are met. +*/ + : iOffset(aOffset), iChunkSize(aMinLength) + { + __ASSERT_ALWAYS(iOffset>=0, HEAP_PANIC(ETHeapNewBadOffset)); + + iChunkHandle = aChunkHandle; + iMinLength = aMinLength; + iMaxLength = aMaxLength; + + // If the user has explicitly specified 0 as the aGrowBy value, set it to 1 so that it will be rounded up to the nearst page size + if (aGrowBy == 0) + aGrowBy = 1; + GET_PAGE_SIZE(iPageSize); + iGrowBy = _ALIGN_UP(aGrowBy, iPageSize); + + Construct(aSingleThread, aDLOnly, aUseAdjust, aAlign); + } + +RHybridHeap::RHybridHeap(TInt aMaxLength, TInt aAlign, TBool aSingleThread) +/** +Constructor for a fixed heap. We have restrictions in that we have fixed minimum and maximum lengths and cannot grow +and we only use DL allocator. +*/ + : iOffset(0), iChunkSize(aMaxLength) + { + iChunkHandle = NULL; + iMinLength = aMaxLength; + iMaxLength = aMaxLength; + iGrowBy = 0; + + Construct(aSingleThread, ETrue, ETrue, aAlign); + } + +TAny* RHybridHeap::operator new(TUint aSize, TAny* aBase) __NO_THROW +{ + __ASSERT_ALWAYS(aSize>=sizeof(RHybridHeap), HEAP_PANIC(ETHeapNewBadSize)); + RHybridHeap* h = (RHybridHeap*)aBase; + h->iBase = ((TUint8*)aBase) + aSize; + return aBase; +} + +void RHybridHeap::Construct(TBool aSingleThread, TBool aDLOnly, TBool aUseAdjust, TInt aAlign) +{ + iAlign = aAlign ? aAlign : RHybridHeap::ECellAlignment; + __ASSERT_ALWAYS((TUint32)iAlign>=sizeof(TAny*) && __POWER_OF_2(iAlign), HEAP_PANIC(ETHeapNewBadAlignment)); + + // This initialisation cannot be done in RHeap() for compatibility reasons + iTop = NULL; + iFailType = ENone; + iNestingLevel = 0; + iTestData = NULL; + + iHighWaterMark = iMinLength; + iAllocCount = 0; + iFlags = aSingleThread ? ESingleThreaded : 0; + iGrowBy = _ALIGN_UP(iGrowBy, iPageSize); + + if ( iMinLength == iMaxLength ) + { + iFlags |= EFixedSize; + aDLOnly = ETrue; + } +#ifndef __KERNEL_MODE__ +#ifdef DELAYED_SLAB_THRESHOLD + iSlabInitThreshold = DELAYED_SLAB_THRESHOLD; +#else + iSlabInitThreshold = 0; +#endif // DELAYED_SLAB_THRESHOLD + iUseAdjust = aUseAdjust; + iDLOnly = aDLOnly; +#else + (void)aUseAdjust; +#endif + // Initialise suballocators + // if DL only is required then it cannot allocate slab or page memory + // so these sub-allocators should be disabled. Otherwise initialise with default values + if ( aDLOnly ) + { + Init(0, 0); + } + else + { + Init(SLAB_CONFIG, 16); + } + +#ifdef ENABLE_BTRACE + + TUint32 traceData[4]; + traceData[0] = iMinLength; + traceData[1] = iMaxLength; + traceData[2] = iGrowBy; + traceData[3] = iAlign; + BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 11, traceData, sizeof(traceData)); +#endif + +} + +#ifndef __KERNEL_MODE__ +TInt RHybridHeap::ConstructLock(TUint32 aMode) +{ + TBool duplicateLock = EFalse; + TInt r = KErrNone; + if (!(iFlags & ESingleThreaded)) + { + duplicateLock = aMode & UserHeap::EChunkHeapSwitchTo; + r = iLock.CreateLocal(duplicateLock ? EOwnerThread : EOwnerProcess); + if( r != KErrNone) + { + iChunkHandle = 0; + return r; + } + } + + if ( aMode & UserHeap::EChunkHeapSwitchTo ) + User::SwitchHeap(this); + + iHandles = &iChunkHandle; + if (!(iFlags & ESingleThreaded)) + { + // now change the thread-relative chunk/semaphore handles into process-relative handles + iHandleCount = 2; + if(duplicateLock) + { + RHandleBase s = iLock; + r = iLock.Duplicate(RThread()); + s.Close(); + } + if (r==KErrNone && (aMode & UserHeap::EChunkHeapDuplicate)) + { + r = ((RChunk*)&iChunkHandle)->Duplicate(RThread()); + if (r!=KErrNone) + iLock.Close(), iChunkHandle=0; + } + } + else + { + iHandleCount = 1; + if (aMode & UserHeap::EChunkHeapDuplicate) + r = ((RChunk*)&iChunkHandle)->Duplicate(RThread(), EOwnerThread); + } + + return r; +} +#endif + +void RHybridHeap::Init(TInt aBitmapSlab, TInt aPagePower) +{ + /*Moved code which does initialization */ + iTop = (TUint8*)this + iMinLength; + iBase = Ceiling(iBase, ECellAlignment); // Align iBase address + + __INIT_COUNTERS(0); + // memset(&mparams,0,sizeof(mparams)); + + InitDlMalloc(iTop - iBase, 0); + +#ifndef __KERNEL_MODE__ + SlabInit(); + iSlabConfigBits = aBitmapSlab; + if ( iChunkSize > iSlabInitThreshold ) + { + iSlabInitThreshold = KMaxTInt32; + SlabConfig(aBitmapSlab); // Delayed slab configuration done + } + if ( aPagePower ) + { + RChunk chunk; + chunk.SetHandle(iChunkHandle); + iMemBase = chunk.Base(); // Store base address for paged allocator + } + + /*10-1K,11-2K,12-4k,13-8K,14-16K,15-32K,16-64K*/ + PagedInit(aPagePower); + +#ifdef ENABLE_BTRACE + TUint32 traceData[3]; + traceData[0] = aBitmapSlab; + traceData[1] = aPagePower; + traceData[2] = GM->iTrimCheck; + BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 0, traceData, sizeof(traceData)); +#endif +#else + (void)aBitmapSlab; + (void)aPagePower; +#endif // __KERNEL_MODE__ + +} + + +TInt RHybridHeap::AllocLen(const TAny* aCell) const +{ + aCell = __GET_DEBUG_DATA_BFR(aCell); + + if (PtrDiff(aCell, this) >= 0) + { + mchunkptr m = MEM2CHUNK(aCell); + return CHUNKSIZE(m) - OVERHEAD_FOR(m) - __DEBUG_HDR_SIZE; + } +#ifndef __KERNEL_MODE__ + if ( aCell ) + { + if (LowBits(aCell, iPageSize) ) + return SlabHeaderSize(slab::SlabFor(aCell)->iHeader) - __DEBUG_HDR_SIZE; + + return PagedSize((void*)aCell) - __DEBUG_HDR_SIZE; + } +#endif + return 0; // NULL pointer situation, should PANIC !! +} + +#ifdef __KERNEL_MODE__ +TAny* RHybridHeap::Alloc(TInt aSize) +{ + __CHECK_THREAD_STATE; + __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); + __SIMULATE_ALLOC_FAIL(return NULL;) + Lock(); + __ALLOC_DEBUG_HEADER(aSize); + TAny* addr = DlMalloc(aSize); + if ( addr ) + { +// iCellCount++; + __SET_DEBUG_DATA(addr, iNestingLevel, ++iAllocCount); + addr = __GET_USER_DATA_BFR(addr); + __INCREMENT_COUNTERS(addr); + memclr(addr, AllocLen(addr)); + } + Unlock(); +#ifdef ENABLE_BTRACE + if (iFlags & ETraceAllocs) + { + if ( addr ) + { + TUint32 traceData[3]; + traceData[0] = AllocLen(addr); + traceData[1] = aSize - __DEBUG_HDR_SIZE; + traceData[2] = 0; + BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)addr, traceData, sizeof(traceData)); + } + else + BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)(aSize - __DEBUG_HDR_SIZE)); + } +#endif + return addr; +} +#else + +TAny* RHybridHeap::Alloc(TInt aSize) +{ + __ASSERT_ALWAYS((TUint)aSize<(KMaxTInt/2),HEAP_PANIC(ETHeapBadAllocatedCellSize)); + __SIMULATE_ALLOC_FAIL(return NULL;) + + TAny* addr; +#ifdef ENABLE_BTRACE + TInt aSubAllocator=0; +#endif + + Lock(); + + __ALLOC_DEBUG_HEADER(aSize); + + if (aSize < iSlabThreshold) + { + TInt ix = iSizeMap[(aSize+3)>>2]; + HEAP_ASSERT(ix != 0xff); + addr = SlabAllocate(iSlabAlloc[ix]); + if ( !addr ) + { // Slab allocation has failed, try to allocate from DL + addr = DlMalloc(aSize); + } +#ifdef ENABLE_BTRACE + else + aSubAllocator=1; +#endif + }else if((aSize >> iPageThreshold)==0) + { + addr = DlMalloc(aSize); + } + else + { + addr = PagedAllocate(aSize); + if ( !addr ) + { // Page allocation has failed, try to allocate from DL + addr = DlMalloc(aSize); + } +#ifdef ENABLE_BTRACE + else + aSubAllocator=2; +#endif + } + + if ( addr ) + { +// iCellCount++; + __SET_DEBUG_DATA(addr, iNestingLevel, ++iAllocCount); + addr = __GET_USER_DATA_BFR(addr); + __INCREMENT_COUNTERS(addr); + } + Unlock(); + +#ifdef ENABLE_BTRACE + if (iFlags & ETraceAllocs) + { + if ( addr ) + { + TUint32 traceData[3]; + traceData[0] = AllocLen(addr); + traceData[1] = aSize - __DEBUG_HDR_SIZE; + traceData[2] = aSubAllocator; + BTraceContextN(BTrace::EHeap, BTrace::EHeapAlloc, (TUint32)this, (TUint32)addr, traceData, sizeof(traceData)); + } + else + BTraceContext8(BTrace::EHeap, BTrace::EHeapAllocFail, (TUint32)this, (TUint32)(aSize - __DEBUG_HDR_SIZE)); + } +#endif + + return addr; +} +#endif // __KERNEL_MODE__ + +#ifndef __KERNEL_MODE__ +TInt RHybridHeap::Compress() +{ + if ( IS_FIXED_HEAP ) + return 0; + + Lock(); + TInt Reduced = SysTrim(GM, 0); + if (iSparePage) + { + Unmap(iSparePage, iPageSize); + iSparePage = 0; + Reduced += iPageSize; + } + Unlock(); + return Reduced; +} +#endif + +void RHybridHeap::Free(TAny* aPtr) +{ + __CHECK_THREAD_STATE; + if ( !aPtr ) + return; +#ifdef ENABLE_BTRACE + TInt aSubAllocator=0; +#endif + Lock(); + + aPtr = __GET_DEBUG_DATA_BFR(aPtr); + +#ifndef __KERNEL_MODE__ + if (PtrDiff(aPtr, this) >= 0) + { +#endif + __DL_BFR_CHECK(GM, aPtr); + __DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr)); + __ZAP_CELL(aPtr); + DlFree( aPtr); +#ifndef __KERNEL_MODE__ + } + + else if ( LowBits(aPtr, iPageSize) == 0 ) + { +#ifdef ENABLE_BTRACE + aSubAllocator = 2; +#endif + __PAGE_BFR_CHECK(aPtr); + __DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr)); + PagedFree(aPtr); + } + else + { +#ifdef ENABLE_BTRACE + aSubAllocator = 1; +#endif + TUint32 bm[4]; + __SLAB_BFR_CHECK(slab::SlabFor(aPtr),aPtr,bm); + __DECREMENT_COUNTERS(__GET_USER_DATA_BFR(aPtr)); + __ZAP_CELL(aPtr); + SlabFree(aPtr); + } +#endif // __KERNEL_MODE__ +// iCellCount--; + Unlock(); +#ifdef ENABLE_BTRACE + if (iFlags & ETraceAllocs) + { + TUint32 traceData; + traceData = aSubAllocator; + BTraceContextN(BTrace::EHeap, BTrace::EHeapFree, (TUint32)this, (TUint32)__GET_USER_DATA_BFR(aPtr), &traceData, sizeof(traceData)); + } +#endif +} + +#ifndef __KERNEL_MODE__ +void RHybridHeap::Reset() +/** +Frees all allocated cells on this heap. +*/ +{ + Lock(); + if ( !IS_FIXED_HEAP ) + { + if ( GM->iSeg.iSize > (iMinLength - sizeof(*this)) ) + Unmap(GM->iSeg.iBase + (iMinLength - sizeof(*this)), (GM->iSeg.iSize - (iMinLength - sizeof(*this)))); + ResetBitmap(); + if ( !iDLOnly ) + Init(iSlabConfigBits, iPageThreshold); + else + Init(0,0); + } + else Init(0,0); + Unlock(); +} +#endif + +TAny* RHybridHeap::ReAllocImpl(TAny* aPtr, TInt aSize, TInt aMode) +{ + // First handle special case of calling reallocate with NULL aPtr + if (!aPtr) + { + if (( aMode & ENeverMove ) == 0 ) + { + aPtr = Alloc(aSize - __DEBUG_HDR_SIZE); + aPtr = __GET_DEBUG_DATA_BFR(aPtr); + } + return aPtr; + } + + TInt oldsize = AllocLen(__GET_USER_DATA_BFR(aPtr)) + __DEBUG_HDR_SIZE; + + // Insist on geometric growth when reallocating memory, this reduces copying and fragmentation + // generated during arithmetic growth of buffer/array/vector memory + // Experiments have shown that 25% is a good threshold for this policy + if (aSize <= oldsize) + { + if (aSize >= oldsize - (oldsize>>2)) + return aPtr; // don't change if >75% original size + } + else + { + __SIMULATE_ALLOC_FAIL(return NULL;) + if (aSize < oldsize + (oldsize>>2)) + { + aSize = _ALIGN_UP(oldsize + (oldsize>>2), 4); // grow to at least 125% original size + } + } + __DEBUG_SAVE(aPtr); + + TAny* newp; +#ifdef __KERNEL_MODE__ + Lock(); + __DL_BFR_CHECK(GM, aPtr); + newp = DlRealloc(aPtr, aSize, aMode); + Unlock(); + if ( newp ) + { + if ( aSize > oldsize ) + memclr(((TUint8*)newp) + oldsize, (aSize-oldsize)); // Buffer has grown in place, clear extra + __DEBUG_RESTORE(newp); + __UPDATE_ALLOC_COUNT(aPtr, newp, ++iAllocCount); + __UPDATE_TOTAL_ALLOC(newp, oldsize); + } +#else + // Decide how to reallocate based on (a) the current cell location, (b) the mode requested and (c) the new size + if ( PtrDiff(aPtr, this) >= 0 ) + { // current cell in Doug Lea iArena + if ( (aMode & ENeverMove) + || + (!(aMode & EAllowMoveOnShrink) && (aSize < oldsize)) + || + ((aSize >= iSlabThreshold) && ((aSize >> iPageThreshold) == 0)) ) + { + Lock(); + __DL_BFR_CHECK(GM, aPtr); + newp = DlRealloc(aPtr, aSize, aMode); // old and new in DL allocator + Unlock(); + __DEBUG_RESTORE(newp); + __UPDATE_ALLOC_COUNT(aPtr,newp, ++iAllocCount); + __UPDATE_TOTAL_ALLOC(newp, oldsize); + return newp; + } + } + else if (LowBits(aPtr, iPageSize) == 0) + { // current cell in paged iArena + if ( (aMode & ENeverMove) + || + (!(aMode & EAllowMoveOnShrink) && (aSize < oldsize)) + || + ((aSize >> iPageThreshold) != 0) ) + { + Lock(); + __PAGE_BFR_CHECK(aPtr); + newp = PagedReallocate(aPtr, aSize, aMode); // old and new in paged allocator + Unlock(); + __DEBUG_RESTORE(newp); + __UPDATE_ALLOC_COUNT(aPtr,newp, ++iAllocCount); + __UPDATE_TOTAL_ALLOC(newp, oldsize); + return newp; + } + } + else + { // current cell in slab iArena + TUint32 bm[4]; + Lock(); + __SLAB_BFR_CHECK(slab::SlabFor(aPtr), aPtr, bm); + Unlock(); + if ( aSize <= oldsize) + return aPtr; + if (aMode & ENeverMove) + return NULL; // cannot grow in slab iArena + // just use alloc/copy/free... + } + + // fallback to allocate and copy + // shouldn't get here if we cannot move the cell + // __ASSERT(mode == emobile || (mode==efixshrink && size>oldsize)); + + newp = Alloc(aSize - __DEBUG_HDR_SIZE); + newp = __GET_DEBUG_DATA_BFR(newp); + if (newp) + { + memcpy(newp, aPtr, oldsize +//#define DEBUG_REALLOC +#ifdef DEBUG_REALLOC +#include +#endif + +inline void RHybridHeap::InitBins(mstate m) +{ + /* Establish circular links for iSmallBins */ + bindex_t i; + for (i = 0; i < NSMALLBINS; ++i) { + sbinptr bin = SMALLBIN_AT(m,i); + bin->iFd = bin->iBk = bin; + } + } +/* ---------------------------- malloc support --------------------------- */ + +/* allocate a large request from the best fitting chunk in a treebin */ +void* RHybridHeap::TmallocLarge(mstate m, size_t nb) { + tchunkptr v = 0; + size_t rsize = -nb; /* Unsigned negation */ + tchunkptr t; + bindex_t idx; + ComputeTreeIndex(nb, idx); + + if ((t = *TREEBIN_AT(m, idx)) != 0) + { + /* Traverse tree for this bin looking for node with size == nb */ + size_t sizebits = nb << LEFTSHIFT_FOR_TREE_INDEX(idx); + tchunkptr rst = 0; /* The deepest untaken right subtree */ + for (;;) + { + tchunkptr rt; + size_t trem = CHUNKSIZE(t) - nb; + if (trem < rsize) + { + v = t; + if ((rsize = trem) == 0) + break; + } + rt = t->iChild[1]; + t = t->iChild[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; + if (rt != 0 && rt != t) + rst = rt; + if (t == 0) + { + t = rst; /* set t to least subtree holding sizes > nb */ + break; + } + sizebits <<= 1; + } + } + if (t == 0 && v == 0) + { /* set t to root of next non-empty treebin */ + binmap_t leftbits = LEFT_BITS(IDX2BIT(idx)) & m->iTreeMap; + if (leftbits != 0) + { + bindex_t i; + binmap_t leastbit = LEAST_BIT(leftbits); + ComputeBit2idx(leastbit, i); + t = *TREEBIN_AT(m, i); + } + } + while (t != 0) + { /* Find smallest of tree or subtree */ + size_t trem = CHUNKSIZE(t) - nb; + if (trem < rsize) { + rsize = trem; + v = t; + } + t = LEFTMOST_CHILD(t); + } + /* If iDv is a better fit, return 0 so malloc will use it */ + if (v != 0 && rsize < (size_t)(m->iDvSize - nb)) + { + if (RTCHECK(OK_ADDRESS(m, v))) + { /* split */ + mchunkptr r = CHUNK_PLUS_OFFSET(v, nb); + HEAP_ASSERT(CHUNKSIZE(v) == rsize + nb); + if (RTCHECK(OK_NEXT(v, r))) + { + UnlinkLargeChunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + SET_INUSE_AND_PINUSE(m, v, (rsize + nb)); + else + { + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, v, nb); + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize); + InsertChunk(m, r, rsize); + } + return CHUNK2MEM(v); + } + } + // CORRUPTION_ERROR_ACTION(m); + } + return 0; + } + +/* allocate a small request from the best fitting chunk in a treebin */ +void* RHybridHeap::TmallocSmall(mstate m, size_t nb) +{ + tchunkptr t, v; + size_t rsize; + bindex_t i; + binmap_t leastbit = LEAST_BIT(m->iTreeMap); + ComputeBit2idx(leastbit, i); + + v = t = *TREEBIN_AT(m, i); + rsize = CHUNKSIZE(t) - nb; + + while ((t = LEFTMOST_CHILD(t)) != 0) + { + size_t trem = CHUNKSIZE(t) - nb; + if (trem < rsize) + { + rsize = trem; + v = t; + } + } + + if (RTCHECK(OK_ADDRESS(m, v))) + { + mchunkptr r = CHUNK_PLUS_OFFSET(v, nb); + HEAP_ASSERT(CHUNKSIZE(v) == rsize + nb); + if (RTCHECK(OK_NEXT(v, r))) + { + UnlinkLargeChunk(m, v); + if (rsize < MIN_CHUNK_SIZE) + SET_INUSE_AND_PINUSE(m, v, (rsize + nb)); + else + { + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, v, nb); + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize); + ReplaceDv(m, r, rsize); + } + return CHUNK2MEM(v); + } + } + // CORRUPTION_ERROR_ACTION(m); + // return 0; + } + +inline void RHybridHeap::InitTop(mstate m, mchunkptr p, size_t psize) +{ + /* Ensure alignment */ + size_t offset = ALIGN_OFFSET(CHUNK2MEM(p)); + p = (mchunkptr)((TUint8*)p + offset); + psize -= offset; + m->iTop = p; + m->iTopSize = psize; + p->iHead = psize | PINUSE_BIT; + /* set size of fake trailing chunk holding overhead space only once */ + mchunkptr chunkPlusOff = CHUNK_PLUS_OFFSET(p, psize); + chunkPlusOff->iHead = TOP_FOOT_SIZE; + m->iTrimCheck = KHeapShrinkHysRatio*(iGrowBy>>8); +} + + +/* Unlink the first chunk from a smallbin */ +inline void RHybridHeap::UnlinkFirstSmallChunk(mstate M,mchunkptr B,mchunkptr P,bindex_t& I) +{ + mchunkptr F = P->iFd; + HEAP_ASSERT(P != B); + HEAP_ASSERT(P != F); + HEAP_ASSERT(CHUNKSIZE(P) == SMALL_INDEX2SIZE(I)); + if (B == F) + CLEAR_SMALLMAP(M, I); + else if (RTCHECK(OK_ADDRESS(M, F))) + { + B->iFd = F; + F->iBk = B; + } + else + { + CORRUPTION_ERROR_ACTION(M); + } +} +/* Link a free chunk into a smallbin */ +inline void RHybridHeap::InsertSmallChunk(mstate M,mchunkptr P, size_t S) +{ + bindex_t I = SMALL_INDEX(S); + mchunkptr B = SMALLBIN_AT(M, I); + mchunkptr F = B; + HEAP_ASSERT(S >= MIN_CHUNK_SIZE); + if (!SMALLMAP_IS_MARKED(M, I)) + MARK_SMALLMAP(M, I); + else if (RTCHECK(OK_ADDRESS(M, B->iFd))) + F = B->iFd; + else + { + CORRUPTION_ERROR_ACTION(M); + } + B->iFd = P; + F->iBk = P; + P->iFd = F; + P->iBk = B; +} + + +inline void RHybridHeap::InsertChunk(mstate M,mchunkptr P,size_t S) +{ + if (IS_SMALL(S)) + InsertSmallChunk(M, P, S); + else + { + tchunkptr TP = (tchunkptr)(P); InsertLargeChunk(M, TP, S); + } +} + +inline void RHybridHeap::UnlinkLargeChunk(mstate M,tchunkptr X) +{ + tchunkptr XP = X->iParent; + tchunkptr R; + if (X->iBk != X) + { + tchunkptr F = X->iFd; + R = X->iBk; + if (RTCHECK(OK_ADDRESS(M, F))) + { + F->iBk = R; + R->iFd = F; + } + else + { + CORRUPTION_ERROR_ACTION(M); + } + } + else + { + tchunkptr* RP; + if (((R = *(RP = &(X->iChild[1]))) != 0) || + ((R = *(RP = &(X->iChild[0]))) != 0)) + { + tchunkptr* CP; + while ((*(CP = &(R->iChild[1])) != 0) || + (*(CP = &(R->iChild[0])) != 0)) + { + R = *(RP = CP); + } + if (RTCHECK(OK_ADDRESS(M, RP))) + *RP = 0; + else + { + CORRUPTION_ERROR_ACTION(M); + } + } + } + if (XP != 0) + { + tbinptr* H = TREEBIN_AT(M, X->iIndex); + if (X == *H) + { + if ((*H = R) == 0) + CLEAR_TREEMAP(M, X->iIndex); + } + else if (RTCHECK(OK_ADDRESS(M, XP))) + { + if (XP->iChild[0] == X) + XP->iChild[0] = R; + else + XP->iChild[1] = R; + } + else + CORRUPTION_ERROR_ACTION(M); + if (R != 0) + { + if (RTCHECK(OK_ADDRESS(M, R))) + { + tchunkptr C0, C1; + R->iParent = XP; + if ((C0 = X->iChild[0]) != 0) + { + if (RTCHECK(OK_ADDRESS(M, C0))) + { + R->iChild[0] = C0; + C0->iParent = R; + } + else + CORRUPTION_ERROR_ACTION(M); + } + if ((C1 = X->iChild[1]) != 0) + { + if (RTCHECK(OK_ADDRESS(M, C1))) + { + R->iChild[1] = C1; + C1->iParent = R; + } + else + CORRUPTION_ERROR_ACTION(M); + } + } + else + CORRUPTION_ERROR_ACTION(M); + } + } +} + +/* Unlink a chunk from a smallbin */ +inline void RHybridHeap::UnlinkSmallChunk(mstate M, mchunkptr P,size_t S) +{ + mchunkptr F = P->iFd; + mchunkptr B = P->iBk; + bindex_t I = SMALL_INDEX(S); + HEAP_ASSERT(P != B); + HEAP_ASSERT(P != F); + HEAP_ASSERT(CHUNKSIZE(P) == SMALL_INDEX2SIZE(I)); + if (F == B) + CLEAR_SMALLMAP(M, I); + else if (RTCHECK((F == SMALLBIN_AT(M,I) || OK_ADDRESS(M, F)) && + (B == SMALLBIN_AT(M,I) || OK_ADDRESS(M, B)))) + { + F->iBk = B; + B->iFd = F; + } + else + { + CORRUPTION_ERROR_ACTION(M); + } +} + +inline void RHybridHeap::UnlinkChunk(mstate M, mchunkptr P, size_t S) +{ + if (IS_SMALL(S)) + UnlinkSmallChunk(M, P, S); + else + { + tchunkptr TP = (tchunkptr)(P); UnlinkLargeChunk(M, TP); + } +} + +// For DL debug functions +void RHybridHeap::DoComputeTreeIndex(size_t S, bindex_t& I) +{ + ComputeTreeIndex(S, I); +} + +inline void RHybridHeap::ComputeTreeIndex(size_t S, bindex_t& I) +{ + size_t X = S >> TREEBIN_SHIFT; + if (X == 0) + I = 0; + else if (X > 0xFFFF) + I = NTREEBINS-1; + else + { + unsigned int Y = (unsigned int)X; + unsigned int N = ((Y - 0x100) >> 16) & 8; + unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4; + N += K; + N += K = (((Y <<= K) - 0x4000) >> 16) & 2; + K = 14 - N + ((Y <<= K) >> 15); + I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)); + } +} + +/* ------------------------- Operations on trees ------------------------- */ + +/* Insert chunk into tree */ +inline void RHybridHeap::InsertLargeChunk(mstate M,tchunkptr X,size_t S) +{ + tbinptr* H; + bindex_t I; + ComputeTreeIndex(S, I); + H = TREEBIN_AT(M, I); + X->iIndex = I; + X->iChild[0] = X->iChild[1] = 0; + if (!TREEMAP_IS_MARKED(M, I)) + { + MARK_TREEMAP(M, I); + *H = X; + X->iParent = (tchunkptr)H; + X->iFd = X->iBk = X; + } + else + { + tchunkptr T = *H; + size_t K = S << LEFTSHIFT_FOR_TREE_INDEX(I); + for (;;) + { + if (CHUNKSIZE(T) != S) { + tchunkptr* C = &(T->iChild[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]); + K <<= 1; + if (*C != 0) + T = *C; + else if (RTCHECK(OK_ADDRESS(M, C))) + { + *C = X; + X->iParent = T; + X->iFd = X->iBk = X; + break; + } + else + { + CORRUPTION_ERROR_ACTION(M); + break; + } + } + else + { + tchunkptr F = T->iFd; + if (RTCHECK(OK_ADDRESS(M, T) && OK_ADDRESS(M, F))) + { + T->iFd = F->iBk = X; + X->iFd = F; + X->iBk = T; + X->iParent = 0; + break; + } + else + { + CORRUPTION_ERROR_ACTION(M); + break; + } + } + } + } +} + +/* +Unlink steps: + +1. If x is a chained node, unlink it from its same-sized iFd/iBk links +and choose its iBk node as its replacement. +2. If x was the last node of its size, but not a leaf node, it must +be replaced with a leaf node (not merely one with an open left or +right), to make sure that lefts and rights of descendents +correspond properly to bit masks. We use the rightmost descendent +of x. We could use any other leaf, but this is easy to locate and +tends to counteract removal of leftmosts elsewhere, and so keeps +paths shorter than minimally guaranteed. This doesn't loop much +because on average a node in a tree is near the bottom. +3. If x is the base of a chain (i.e., has iParent links) relink +x's iParent and children to x's replacement (or null if none). +*/ + +/* Replace iDv node, binning the old one */ +/* Used only when iDvSize known to be small */ +inline void RHybridHeap::ReplaceDv(mstate M, mchunkptr P, size_t S) +{ + size_t DVS = M->iDvSize; + if (DVS != 0) + { + mchunkptr DV = M->iDv; + HEAP_ASSERT(IS_SMALL(DVS)); + InsertSmallChunk(M, DV, DVS); + } + M->iDvSize = S; + M->iDv = P; +} + + +inline void RHybridHeap::ComputeBit2idx(binmap_t X,bindex_t& I) +{ + unsigned int Y = X - 1; + unsigned int K = Y >> (16-4) & 16; + unsigned int N = K; Y >>= K; + N += K = Y >> (8-3) & 8; Y >>= K; + N += K = Y >> (4-2) & 4; Y >>= K; + N += K = Y >> (2-1) & 2; Y >>= K; + N += K = Y >> (1-0) & 1; Y >>= K; + I = (bindex_t)(N + Y); +} + + + +int RHybridHeap::SysTrim(mstate m, size_t pad) +{ + size_t extra = 0; + + if ( IS_INITIALIZED(m) ) + { + pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ + + if (m->iTopSize > pad) + { + extra = Floor(m->iTopSize - pad, iPageSize); + if ( (m->iSeg.iSize - extra) < (iMinLength - sizeof(*this)) ) + { + if ( m->iSeg.iSize > (iMinLength - sizeof(*this)) ) + extra = Floor(m->iSeg.iSize - (iMinLength - sizeof(*this)), iPageSize); /* do not shrink heap below min length */ + else extra = 0; + } + + if ( extra ) + { + Unmap(m->iSeg.iBase + m->iSeg.iSize - extra, extra); + + m->iSeg.iSize -= extra; + InitTop(m, m->iTop, m->iTopSize - extra); + CHECK_TOP_CHUNK(m, m->iTop); + } + } + + } + + return extra; +} + +/* Get memory from system using MORECORE */ + +void* RHybridHeap::SysAlloc(mstate m, size_t nb) +{ + HEAP_ASSERT(m->iTop); + /* Subtract out existing available iTop space from MORECORE request. */ +// size_t asize = _ALIGN_UP(nb - m->iTopSize + TOP_FOOT_SIZE + SIZE_T_ONE, iGrowBy); + TInt asize = _ALIGN_UP(nb - m->iTopSize + SYS_ALLOC_PADDING, iGrowBy); // From DLA version 2.8.4 + + char* br = (char*)Map(m->iSeg.iBase+m->iSeg.iSize, asize); + if (!br) + return 0; + HEAP_ASSERT(br == (char*)m->iSeg.iBase+m->iSeg.iSize); + + /* Merge with an existing segment */ + m->iSeg.iSize += asize; + InitTop(m, m->iTop, m->iTopSize + asize); + + if (nb < m->iTopSize) + { /* Allocate from new or extended iTop space */ + size_t rsize = m->iTopSize -= nb; + mchunkptr p = m->iTop; + mchunkptr r = m->iTop = CHUNK_PLUS_OFFSET(p, nb); + r->iHead = rsize | PINUSE_BIT; + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(m, p, nb); + CHECK_TOP_CHUNK(m, m->iTop); + CHECK_MALLOCED_CHUNK(m, CHUNK2MEM(p), nb); + return CHUNK2MEM(p); + } + + return 0; +} + + +void RHybridHeap::InitDlMalloc(size_t capacity, int /*locked*/) +{ + memset(GM,0,sizeof(malloc_state)); + // The maximum amount that can be allocated can be calculated as:- + // 2^sizeof(size_t) - sizeof(malloc_state) - TOP_FOOT_SIZE - page Size(all accordingly padded) + // If the capacity exceeds this, no allocation will be done. + GM->iSeg.iBase = iBase; + GM->iSeg.iSize = capacity; + InitBins(GM); + InitTop(GM, (mchunkptr)iBase, capacity - TOP_FOOT_SIZE); +} + +void* RHybridHeap::DlMalloc(size_t bytes) +{ + /* + Basic algorithm: + If a small request (< 256 bytes minus per-chunk overhead): + 1. If one exists, use a remainderless chunk in associated smallbin. + (Remainderless means that there are too few excess bytes to + represent as a chunk.) + 2. If it is big enough, use the iDv chunk, which is normally the + chunk adjacent to the one used for the most recent small request. + 3. If one exists, split the smallest available chunk in a bin, + saving remainder in iDv. + 4. If it is big enough, use the iTop chunk. + 5. If available, get memory from system and use it + Otherwise, for a large request: + 1. Find the smallest available binned chunk that fits, and use it + if it is better fitting than iDv chunk, splitting if necessary. + 2. If better fitting than any binned chunk, use the iDv chunk. + 3. If it is big enough, use the iTop chunk. + 4. If request size >= mmap threshold, try to directly mmap this chunk. + 5. If available, get memory from system and use it +*/ + void* mem; + size_t nb; + if (bytes <= MAX_SMALL_REQUEST) + { + bindex_t idx; + binmap_t smallbits; + nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : PAD_REQUEST(bytes); + idx = SMALL_INDEX(nb); + smallbits = GM->iSmallMap >> idx; + + if ((smallbits & 0x3U) != 0) + { /* Remainderless fit to a smallbin. */ + mchunkptr b, p; + idx += ~smallbits & 1; /* Uses next bin if idx empty */ + b = SMALLBIN_AT(GM, idx); + p = b->iFd; + HEAP_ASSERT(CHUNKSIZE(p) == SMALL_INDEX2SIZE(idx)); + UnlinkFirstSmallChunk(GM, b, p, idx); + SET_INUSE_AND_PINUSE(GM, p, SMALL_INDEX2SIZE(idx)); + mem = CHUNK2MEM(p); + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + + else if (nb > GM->iDvSize) + { + if (smallbits != 0) + { /* Use chunk in next nonempty smallbin */ + mchunkptr b, p, r; + size_t rsize; + bindex_t i; + binmap_t leftbits = (smallbits << idx) & LEFT_BITS(IDX2BIT(idx)); + binmap_t leastbit = LEAST_BIT(leftbits); + ComputeBit2idx(leastbit, i); + b = SMALLBIN_AT(GM, i); + p = b->iFd; + HEAP_ASSERT(CHUNKSIZE(p) == SMALL_INDEX2SIZE(i)); + UnlinkFirstSmallChunk(GM, b, p, i); + rsize = SMALL_INDEX2SIZE(i) - nb; + /* Fit here cannot be remainderless if 4byte sizes */ + if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) + SET_INUSE_AND_PINUSE(GM, p, SMALL_INDEX2SIZE(i)); + else + { + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb); + r = CHUNK_PLUS_OFFSET(p, nb); + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize); + ReplaceDv(GM, r, rsize); + } + mem = CHUNK2MEM(p); + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + + else if (GM->iTreeMap != 0 && (mem = TmallocSmall(GM, nb)) != 0) + { + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + } + } + else if (bytes >= MAX_REQUEST) + nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ + else + { + nb = PAD_REQUEST(bytes); + if (GM->iTreeMap != 0 && (mem = TmallocLarge(GM, nb)) != 0) + { + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + } + + if (nb <= GM->iDvSize) + { + size_t rsize = GM->iDvSize - nb; + mchunkptr p = GM->iDv; + if (rsize >= MIN_CHUNK_SIZE) + { /* split iDv */ + mchunkptr r = GM->iDv = CHUNK_PLUS_OFFSET(p, nb); + GM->iDvSize = rsize; + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(r, rsize); + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb); + } + else + { /* exhaust iDv */ + size_t dvs = GM->iDvSize; + GM->iDvSize = 0; + GM->iDv = 0; + SET_INUSE_AND_PINUSE(GM, p, dvs); + } + mem = CHUNK2MEM(p); + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + + else if (nb < GM->iTopSize) + { /* Split iTop */ + size_t rsize = GM->iTopSize -= nb; + mchunkptr p = GM->iTop; + mchunkptr r = GM->iTop = CHUNK_PLUS_OFFSET(p, nb); + r->iHead = rsize | PINUSE_BIT; + SET_SIZE_AND_PINUSE_OF_INUSE_CHUNK(GM, p, nb); + mem = CHUNK2MEM(p); + CHECK_TOP_CHUNK(GM, GM->iTop); + CHECK_MALLOCED_CHUNK(GM, mem, nb); + return mem; + } + + return SysAlloc(GM, nb); +} + + +void RHybridHeap::DlFree(void* mem) +{ + /* + Consolidate freed chunks with preceding or succeeding bordering + free chunks, if they exist, and then place in a bin. Intermixed + with special cases for iTop, iDv, mmapped chunks, and usage errors. +*/ + mchunkptr p = MEM2CHUNK(mem); + CHECK_INUSE_CHUNK(GM, p); + if (RTCHECK(OK_ADDRESS(GM, p) && OK_CINUSE(p))) + { + size_t psize = CHUNKSIZE(p); + mchunkptr next = CHUNK_PLUS_OFFSET(p, psize); + if (!PINUSE(p)) + { + size_t prevsize = p->iPrevFoot; + mchunkptr prev = CHUNK_MINUS_OFFSET(p, prevsize); + psize += prevsize; + p = prev; + if (RTCHECK(OK_ADDRESS(GM, prev))) + { /* consolidate backward */ + if (p != GM->iDv) + { + UnlinkChunk(GM, p, prevsize); + } + else if ((next->iHead & INUSE_BITS) == INUSE_BITS) + { + GM->iDvSize = psize; + SET_FREE_WITH_PINUSE(p, psize, next); + return; + } + } + else + { + USAGE_ERROR_ACTION(GM, p); + return; + } + } + + if (RTCHECK(OK_NEXT(p, next) && OK_PINUSE(next))) + { + if (!CINUSE(next)) + { /* consolidate forward */ + if (next == GM->iTop) + { + size_t tsize = GM->iTopSize += psize; + GM->iTop = p; + p->iHead = tsize | PINUSE_BIT; + if (p == GM->iDv) + { + GM->iDv = 0; + GM->iDvSize = 0; + } + if ( !IS_FIXED_HEAP && SHOULD_TRIM(GM, tsize) ) + SysTrim(GM, 0); + return; + } + else if (next == GM->iDv) + { + size_t dsize = GM->iDvSize += psize; + GM->iDv = p; + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, dsize); + return; + } + else + { + size_t nsize = CHUNKSIZE(next); + psize += nsize; + UnlinkChunk(GM, next, nsize); + SET_SIZE_AND_PINUSE_OF_FREE_CHUNK(p, psize); + if (p == GM->iDv) + { + GM->iDvSize = psize; + return; + } + } + } + else + SET_FREE_WITH_PINUSE(p, psize, next); + InsertChunk(GM, p, psize); + CHECK_FREE_CHUNK(GM, p); + return; + } + } +} + + +void* RHybridHeap::DlRealloc(void* oldmem, size_t bytes, TInt mode) +{ + mchunkptr oldp = MEM2CHUNK(oldmem); + size_t oldsize = CHUNKSIZE(oldp); + mchunkptr next = CHUNK_PLUS_OFFSET(oldp, oldsize); + mchunkptr newp = 0; + void* extra = 0; + + /* Try to either shrink or extend into iTop. Else malloc-copy-free */ + + if (RTCHECK(OK_ADDRESS(GM, oldp) && OK_CINUSE(oldp) && + OK_NEXT(oldp, next) && OK_PINUSE(next))) + { + size_t nb = REQUEST2SIZE(bytes); + if (oldsize >= nb) { /* already big enough */ + size_t rsize = oldsize - nb; + newp = oldp; + if (rsize >= MIN_CHUNK_SIZE) + { + mchunkptr remainder = CHUNK_PLUS_OFFSET(newp, nb); + SET_INUSE(GM, newp, nb); +// SET_INUSE(GM, remainder, rsize); + SET_INUSE_AND_PINUSE(GM, remainder, rsize); // corrected in original DLA version V2.8.4 + extra = CHUNK2MEM(remainder); + } + } + else if (next == GM->iTop && oldsize + GM->iTopSize > nb) + { + /* Expand into iTop */ + size_t newsize = oldsize + GM->iTopSize; + size_t newtopsize = newsize - nb; + mchunkptr newtop = CHUNK_PLUS_OFFSET(oldp, nb); + SET_INUSE(GM, oldp, nb); + newtop->iHead = newtopsize |PINUSE_BIT; + GM->iTop = newtop; + GM->iTopSize = newtopsize; + newp = oldp; + } + } + else + { + USAGE_ERROR_ACTION(GM, oldmem); + } + + if (newp != 0) + { + if (extra != 0) + { + DlFree(extra); + } + CHECK_INUSE_CHUNK(GM, newp); + return CHUNK2MEM(newp); + } + else + { + if ( mode & ENeverMove ) + return 0; // cannot move + void* newmem = DlMalloc(bytes); + if (newmem != 0) + { + size_t oc = oldsize - OVERHEAD_FOR(oldp); + memcpy(newmem, oldmem, (oc < bytes)? oc : bytes); + DlFree(oldmem); + } + return newmem; + } + // return 0; +} + +size_t RHybridHeap::DlInfo(struct HeapInfo* i, SWalkInfo* wi) const +{ + TInt max = ((GM->iTopSize-1) & ~CHUNK_ALIGN_MASK) - CHUNK_OVERHEAD; + if ( max < 0 ) + max = 0; + else ++i->iFreeN; // iTop always free + i->iFreeBytes += max; + + Walk(wi, GM->iTop, max, EGoodFreeCell, EDougLeaAllocator); // Introduce DL iTop buffer to the walk function + + for (mchunkptr q = ALIGN_AS_CHUNK(GM->iSeg.iBase); q != GM->iTop; q = NEXT_CHUNK(q)) + { + TInt sz = CHUNKSIZE(q); + if (!CINUSE(q)) + { + if ( sz > max ) + max = sz; + i->iFreeBytes += sz; + ++i->iFreeN; + Walk(wi, CHUNK2MEM(q), sz, EGoodFreeCell, EDougLeaAllocator); // Introduce DL free buffer to the walk function + } + else + { + i->iAllocBytes += sz - CHUNK_OVERHEAD; + ++i->iAllocN; + Walk(wi, CHUNK2MEM(q), (sz- CHUNK_OVERHEAD), EGoodAllocatedCell, EDougLeaAllocator); // Introduce DL allocated buffer to the walk function + } + } + return max; // return largest available chunk size +} + +// +// get statistics about the state of the allocator +// +TInt RHybridHeap::GetInfo(struct HeapInfo* i, SWalkInfo* wi) const +{ + memset(i,0,sizeof(HeapInfo)); + i->iFootprint = iChunkSize; + i->iMaxSize = iMaxLength; +#ifndef __KERNEL_MODE__ + PagedInfo(i, wi); + SlabInfo(i, wi); +#endif + return DlInfo(i,wi); +} + +// +// Methods to commit/decommit memory pages from chunk +// + + +void* RHybridHeap::Map(void* p, TInt sz) +// +// allocate pages in the chunk +// if p is NULL, Find an allocate the required number of pages (which must lie in the lower half) +// otherwise commit the pages specified +// +{ + HEAP_ASSERT(sz > 0); + + if ( iChunkSize + sz > iMaxLength) + return 0; + +#ifdef __KERNEL_MODE__ + + TInt r = ((DChunk*)iChunkHandle)->Adjust(iChunkSize + iOffset + sz); + if (r < 0) + return 0; + + iChunkSize += sz; + +#else + + RChunk chunk; + chunk.SetHandle(iChunkHandle); + if ( p ) + { + TInt r; + if ( iUseAdjust ) + r = chunk.Adjust(iChunkSize + sz); + else + { + HEAP_ASSERT(sz == Ceiling(sz, iPageSize)); + HEAP_ASSERT(p == Floor(p, iPageSize)); + r = chunk.Commit(iOffset + PtrDiff(p, this),sz); + } + if (r < 0) + return 0; + } + else + { + TInt r = chunk.Allocate(sz); + if (r < 0) + return 0; + if (r > iOffset) + { + // can't allow page allocations in DL zone + chunk.Decommit(r, sz); + return 0; + } + p = Offset(this, r - iOffset); + } + iChunkSize += sz; + + if (iChunkSize >= iSlabInitThreshold) + { // set up slab system now that heap is large enough + SlabConfig(iSlabConfigBits); + iSlabInitThreshold = KMaxTInt32; + } + +#endif // __KERNEL_MODE__ + +#ifdef ENABLE_BTRACE + if(iChunkSize > iHighWaterMark) + { + iHighWaterMark = Ceiling(iChunkSize,16*iPageSize); + TUint32 traceData[6]; + traceData[0] = iChunkHandle; + traceData[1] = iMinLength; + traceData[2] = iMaxLength; + traceData[3] = sz; + traceData[4] = iChunkSize; + traceData[5] = iHighWaterMark; + BTraceContextN(BTrace::ETest1, 90, (TUint32)this, 33, traceData, sizeof(traceData)); + } +#endif + + return p; +} + +void RHybridHeap::Unmap(void* p, TInt sz) +{ + HEAP_ASSERT(sz > 0); + +#ifdef __KERNEL_MODE__ + + (void)p; + HEAP_ASSERT(sz == Ceiling(sz, iPageSize)); +#if defined(_DEBUG) + TInt r = +#endif + ((DChunk*)iChunkHandle)->Adjust(iChunkSize + iOffset - sz); + HEAP_ASSERT(r >= 0); + +#else + + RChunk chunk; + chunk.SetHandle(iChunkHandle); + if ( iUseAdjust ) + { + HEAP_ASSERT(sz == Ceiling(sz, iPageSize)); +#if defined(_DEBUG) + TInt r = +#endif + chunk.Adjust(iChunkSize - sz); + HEAP_ASSERT(r >= 0); + } + else + { + HEAP_ASSERT(sz == Ceiling(sz, iPageSize)); + HEAP_ASSERT(p == Floor(p, iPageSize)); +#if defined(_DEBUG) + TInt r = +#endif + chunk.Decommit(PtrDiff(p, Offset(this,-iOffset)), sz); + HEAP_ASSERT(r >= 0); + } +#endif // __KERNEL_MODE__ + + iChunkSize -= sz; +} + + +#ifndef __KERNEL_MODE__ +// +// Slab allocator code +// + +//inline slab* slab::SlabFor(void* p) +slab* slab::SlabFor( const void* p) +{ + return (slab*)(Floor(p, SLABSIZE)); +} + +// +// Remove slab s from its tree/heap (not necessarily the root), preserving the address order +// invariant of the heap +// +void RHybridHeap::TreeRemove(slab* s) +{ + slab** r = s->iParent; + slab* c1 = s->iChild1; + slab* c2 = s->iChild2; + for (;;) + { + if (!c2) + { + *r = c1; + if (c1) + c1->iParent = r; + return; + } + if (!c1) + { + *r = c2; + c2->iParent = r; + return; + } + if (c1 > c2) + { + slab* c3 = c1; + c1 = c2; + c2 = c3; + } + slab* newc2 = c1->iChild2; + *r = c1; + c1->iParent = r; + c1->iChild2 = c2; + c2->iParent = &c1->iChild2; + s = c1; + c1 = s->iChild1; + c2 = newc2; + r = &s->iChild1; + } +} +// +// Insert slab s into the tree/heap rooted at r, preserving the address ordering +// invariant of the heap +// +void RHybridHeap::TreeInsert(slab* s,slab** r) +{ + slab* n = *r; + for (;;) + { + if (!n) + { // tree empty + *r = s; + s->iParent = r; + s->iChild1 = s->iChild2 = 0; + break; + } + if (s < n) + { // insert between iParent and n + *r = s; + s->iParent = r; + s->iChild1 = n; + s->iChild2 = 0; + n->iParent = &s->iChild1; + break; + } + slab* c1 = n->iChild1; + slab* c2 = n->iChild2; + if ((c1 - 1) > (c2 - 1)) + { + r = &n->iChild1; + n = c1; + } + else + { + r = &n->iChild2; + n = c2; + } + } +} + +void* RHybridHeap::AllocNewSlab(slabset& allocator) +// +// Acquire and initialise a new slab, returning a cell from the slab +// The strategy is: +// 1. Use the lowest address free slab, if available. This is done by using the lowest slab +// in the page at the root of the iPartialPage heap (which is address ordered). If the +// is now fully used, remove it from the iPartialPage heap. +// 2. Allocate a new page for iSlabs if no empty iSlabs are available +// +{ + page* p = page::PageFor(iPartialPage); + if (!p) + return AllocNewPage(allocator); + + unsigned h = p->iSlabs[0].iHeader; + unsigned pagemap = SlabHeaderPagemap(h); + HEAP_ASSERT(&p->iSlabs[HIBIT(pagemap)] == iPartialPage); + + unsigned slabix = LOWBIT(pagemap); + p->iSlabs[0].iHeader = h &~ (0x100<iSlabs[slabix]); +} + +/**Defination of this functionis not there in proto code***/ +#if 0 +void RHybridHeap::partial_insert(slab* s) +{ + // slab has had first cell freed and needs to be linked back into iPartial tree + slabset& ss = iSlabAlloc[iSizeMap[s->clz]]; + + HEAP_ASSERT(s->used == slabfull); + s->used = ss.fulluse - s->clz; // full-1 loading + TreeInsert(s,&ss.iPartial); + CHECKTREE(&ss.iPartial); +} +/**Defination of this functionis not there in proto code***/ +#endif + +void* RHybridHeap::AllocNewPage(slabset& allocator) +// +// Acquire and initialise a new page, returning a cell from a new slab +// The iPartialPage tree is empty (otherwise we'd have used a slab from there) +// The iPartialPage link is put in the highest addressed slab in the page, and the +// lowest addressed slab is used to fulfill the allocation request +// +{ + page* p = iSparePage; + if (p) + iSparePage = 0; + else + { + p = static_cast(Map(0, iPageSize)); + if (!p) + return 0; + } + HEAP_ASSERT(p == Floor(p, iPageSize)); + // Store page allocated for slab into paged_bitmap (for RHybridHeap::Reset()) + if (!PagedSetSize(p, iPageSize)) + { + Unmap(p, iPageSize); + return 0; + } + p->iSlabs[0].iHeader = ((1<<3) + (1<<2) + (1<<1))<<8; // set pagemap + p->iSlabs[3].iParent = &iPartialPage; + p->iSlabs[3].iChild1 = p->iSlabs[3].iChild2 = 0; + iPartialPage = &p->iSlabs[3]; + return InitNewSlab(allocator,&p->iSlabs[0]); +} + +void RHybridHeap::FreePage(page* p) +// +// Release an unused page to the OS +// A single page is cached for reuse to reduce thrashing +// the OS allocator. +// +{ + HEAP_ASSERT(Ceiling(p, iPageSize) == p); + if (!iSparePage) + { + iSparePage = p; + return; + } + + // unmapped slab page must be cleared from paged_bitmap, too + PagedZapSize(p, iPageSize); // clear page map + + Unmap(p, iPageSize); +} + +void RHybridHeap::FreeSlab(slab* s) +// +// Release an empty slab to the slab manager +// The strategy is: +// 1. The page containing the slab is checked to see the state of the other iSlabs in the page by +// inspecting the pagemap field in the iHeader of the first slab in the page. +// 2. The pagemap is updated to indicate the new unused slab +// 3. If this is the only unused slab in the page then the slab iHeader is used to add the page to +// the iPartialPage tree/heap +// 4. If all the iSlabs in the page are now unused the page is release back to the OS +// 5. If this slab has a higher address than the one currently used to track this page in +// the iPartialPage heap, the linkage is moved to the new unused slab +// +{ + TreeRemove(s); + CHECKTREE(s->iParent); + HEAP_ASSERT(SlabHeaderUsedm4(s->iHeader) == SlabHeaderSize(s->iHeader)-4); + + page* p = page::PageFor(s); + unsigned h = p->iSlabs[0].iHeader; + int slabix = s - &p->iSlabs[0]; + unsigned pagemap = SlabHeaderPagemap(h); + p->iSlabs[0].iHeader = h | (0x100<iSlabs[HIBIT(pagemap)]; + pagemap ^= (1< sl) + { // replace current link with new one. Address-order tree so position stays the same + slab** r = sl->iParent; + slab* c1 = sl->iChild1; + slab* c2 = sl->iChild2; + s->iParent = r; + s->iChild1 = c1; + s->iChild2 = c2; + *r = s; + if (c1) + c1->iParent = &s->iChild1; + if (c2) + c2->iParent = &s->iChild2; + } + CHECK(if (s < sl) s=sl); + } + HEAP_ASSERT(SlabHeaderPagemap(p->iSlabs[0].iHeader) != 0); + HEAP_ASSERT(HIBIT(SlabHeaderPagemap(p->iSlabs[0].iHeader)) == unsigned(s - &p->iSlabs[0])); +} + + +void RHybridHeap::SlabInit() +{ + iSlabThreshold=0; + iPartialPage = 0; + iFullSlab = 0; + iSparePage = 0; + memset(&iSizeMap[0],0xff,sizeof(iSizeMap)); + memset(&iSlabAlloc[0],0,sizeof(iSlabAlloc)); +} + +void RHybridHeap::SlabConfig(unsigned slabbitmap) +{ + HEAP_ASSERT((slabbitmap & ~EOkBits) == 0); + HEAP_ASSERT(MAXSLABSIZE <= 60); + + unsigned int ix = 0xff; + unsigned int bit = 1<<((MAXSLABSIZE>>2)-1); + for (int sz = MAXSLABSIZE; sz >= 0; sz -= 4, bit >>= 1) + { + if (slabbitmap & bit) + { + if (ix == 0xff) + iSlabThreshold=sz+1; + ix = (sz>>2)-1; + } + iSizeMap[sz>>2] = (TUint8) ix; + } +} + + +void* RHybridHeap::SlabAllocate(slabset& ss) +// +// Allocate a cell from the given slabset +// Strategy: +// 1. Take the partially full slab at the iTop of the heap (lowest address). +// 2. If there is no such slab, allocate from a new slab +// 3. If the slab has a non-empty freelist, pop the cell from the front of the list and update the slab +// 4. Otherwise, if the slab is not full, return the cell at the end of the currently used region of +// the slab, updating the slab +// 5. Otherwise, release the slab from the iPartial tree/heap, marking it as 'floating' and go back to +// step 1 +// +{ + for (;;) + { + slab *s = ss.iPartial; + if (!s) + break; + unsigned h = s->iHeader; + unsigned free = h & 0xff; // extract free cell positioning + if (free) + { + HEAP_ASSERT(((free<<2)-sizeof(slabhdr))%SlabHeaderSize(h) == 0); + void* p = Offset(s,free<<2); + free = *(unsigned char*)p; // get next pos in free list + h += (h&0x3C000)<<6; // update usedm4 + h &= ~0xff; + h |= free; // update freelist + s->iHeader = h; + HEAP_ASSERT(SlabHeaderFree(h) == 0 || ((SlabHeaderFree(h)<<2)-sizeof(slabhdr))%SlabHeaderSize(h) == 0); + HEAP_ASSERT(SlabHeaderUsedm4(h) <= 0x3F8u); + HEAP_ASSERT((SlabHeaderUsedm4(h)+4)%SlabHeaderSize(h) == 0); + return p; + } + unsigned h2 = h + ((h&0x3C000)<<6); +// if (h2 < 0xfc00000) + if (h2 < MAXUSEDM4BITS) + { + HEAP_ASSERT((SlabHeaderUsedm4(h2)+4)%SlabHeaderSize(h2) == 0); + s->iHeader = h2; + return Offset(s,(h>>18) + sizeof(unsigned) + sizeof(slabhdr)); + } + h |= FLOATING_BIT; // mark the slab as full-floating + s->iHeader = h; + TreeRemove(s); + slab* c = iFullSlab; // add to full list + iFullSlab = s; + s->iParent = &iFullSlab; + s->iChild1 = c; + s->iChild2 = 0; + if (c) + c->iParent = &s->iChild1; + + CHECKTREE(&ss.iPartial); + // go back and try the next slab... + } + // no iPartial iSlabs found, so allocate from a new slab + return AllocNewSlab(ss); +} + +void RHybridHeap::SlabFree(void* p) +// +// Free a cell from the slab allocator +// Strategy: +// 1. Find the containing slab (round down to nearest 1KB boundary) +// 2. Push the cell into the slab's freelist, and update the slab usage count +// 3. If this is the last allocated cell, free the slab to the main slab manager +// 4. If the slab was full-floating then insert the slab in it's respective iPartial tree +// +{ + HEAP_ASSERT(LowBits(p,3)==0); + slab* s = slab::SlabFor(p); + CHECKSLAB(s,ESlabAllocator,p); + CHECKSLABBFR(s,p); + + unsigned pos = LowBits(p, SLABSIZE); + unsigned h = s->iHeader; + HEAP_ASSERT(SlabHeaderUsedm4(h) != 0x3fC); // slab is empty already + HEAP_ASSERT((pos-sizeof(slabhdr))%SlabHeaderSize(h) == 0); + *(unsigned char*)p = (unsigned char)h; + h &= ~0xFF; + h |= (pos>>2); + unsigned size = h & 0x3C000; + if (int(h) >= 0) + { + h -= size<<6; + if (int(h)>=0) + { + s->iHeader = h; + return; + } + FreeSlab(s); + return; + } + h -= size<<6; + h &= ~FLOATING_BIT; + s->iHeader = h; + slab** full = s->iParent; // remove from full list + slab* c = s->iChild1; + *full = c; + if (c) + c->iParent = full; + + slabset& ss = iSlabAlloc[iSizeMap[size>>14]]; + TreeInsert(s,&ss.iPartial); + CHECKTREE(&ss.iPartial); +} + +void* RHybridHeap::InitNewSlab(slabset& allocator, slab* s) +// +// initialise an empty slab for this allocator and return the fist cell +// pre-condition: the slabset has no iPartial iSlabs for allocation +// +{ + HEAP_ASSERT(allocator.iPartial==0); + TInt size = 4 + ((&allocator-&iSlabAlloc[0])<<2); // infer size from slab allocator address + unsigned h = s->iHeader & 0xF00; // preserve pagemap only + h |= (size<<12); // set size + h |= (size-4)<<18; // set usedminus4 to one object minus 4 + s->iHeader = h; + allocator.iPartial = s; + s->iParent = &allocator.iPartial; + s->iChild1 = s->iChild2 = 0; + return Offset(s,sizeof(slabhdr)); +} + +const unsigned char slab_bitcount[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; + +const unsigned char slab_ext_frag[16] = +{ + 0, + 16 + (1008 % 4), + 16 + (1008 % 8), + 16 + (1008 % 12), + 16 + (1008 % 16), + 16 + (1008 % 20), + 16 + (1008 % 24), + 16 + (1008 % 28), + 16 + (1008 % 32), + 16 + (1008 % 36), + 16 + (1008 % 40), + 16 + (1008 % 44), + 16 + (1008 % 48), + 16 + (1008 % 52), + 16 + (1008 % 56), + 16 + (1008 % 60) +}; + +void RHybridHeap::TreeWalk(slab* const* root, void (*f)(slab*, struct HeapInfo*, SWalkInfo*), struct HeapInfo* i, SWalkInfo* wi) +{ + // iterative walk around the tree at root + + slab* s = *root; + if (!s) + return; + + for (;;) + { + slab* c; + while ((c = s->iChild1) != 0) + s = c; // walk down left side to end + for (;;) + { + f(s, i, wi); + c = s->iChild2; + if (c) + { // one step down right side, now try and walk down left + s = c; + break; + } + for (;;) + { // loop to walk up right side + slab** pp = s->iParent; + if (pp == root) + return; + s = slab::SlabFor(pp); + if (pp == &s->iChild1) + break; + } + } + } +} + +void RHybridHeap::SlabEmptyInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi) +{ + Walk(wi, s, SLABSIZE, EGoodFreeCell, EEmptySlab); // Introduce an empty slab to the walk function + int nslab = slab_bitcount[SlabHeaderPagemap(page::PageFor(s)->iSlabs[0].iHeader)]; + i->iFreeN += nslab; + i->iFreeBytes += nslab << SLABSHIFT; +} + +void RHybridHeap::SlabPartialInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi) +{ + Walk(wi, s, SLABSIZE, EGoodAllocatedCell, EPartialFullSlab); // Introduce a full slab to the walk function + unsigned h = s->iHeader; + unsigned used = SlabHeaderUsedm4(h)+4; + unsigned size = SlabHeaderSize(h); + unsigned free = 1024 - slab_ext_frag[size>>2] - used; + i->iFreeN += (free/size); + i->iFreeBytes += free; + i->iAllocN += (used/size); + i->iAllocBytes += used; +} + +void RHybridHeap::SlabFullInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi) +{ + Walk(wi, s, SLABSIZE, EGoodAllocatedCell, EFullSlab); // Introduce a full slab to the walk function + unsigned h = s->iHeader; + unsigned used = SlabHeaderUsedm4(h)+4; + unsigned size = SlabHeaderSize(h); + HEAP_ASSERT(1024 - slab_ext_frag[size>>2] - used == 0); + i->iAllocN += (used/size); + i->iAllocBytes += used; +} + +void RHybridHeap::SlabInfo(struct HeapInfo* i, SWalkInfo* wi) const +{ + if (iSparePage) + { + i->iFreeBytes += iPageSize; + i->iFreeN = 4; + Walk(wi, iSparePage, iPageSize, EGoodFreeCell, ESlabSpare); // Introduce Slab spare page to the walk function + } + TreeWalk(&iFullSlab, &SlabFullInfo, i, wi); + for (int ix = 0; ix < (MAXSLABSIZE>>2); ++ix) + TreeWalk(&iSlabAlloc[ix].iPartial, &SlabPartialInfo, i, wi); + TreeWalk(&iPartialPage, &SlabEmptyInfo, i, wi); +} + + +// +// Bitmap class implementation for large page allocator +// +inline unsigned char* paged_bitmap::Addr() const {return iBase;} +inline unsigned paged_bitmap::Size() const {return iNbits;} +// + +void paged_bitmap::Init(unsigned char* p, unsigned size, unsigned bit) +{ + iBase = p; + iNbits=size; + int bytes=Ceiling(size,8)>>3; + memset(p,bit?0xff:0,bytes); +} + +inline void paged_bitmap::Set(unsigned ix, unsigned bit) +{ + if (bit) + iBase[ix>>3] |= (1<<(ix&7)); + else + iBase[ix>>3] &= ~(1<<(ix&7)); +} + +inline unsigned paged_bitmap::operator[](unsigned ix) const +{ + return 1U&(iBase[ix>>3] >> (ix&7)); +} + +void paged_bitmap::Setn(unsigned ix, unsigned len, unsigned bit) +{ + int l=len; + while (--l>=0) + Set(ix++,bit); +} + +void paged_bitmap::Set(unsigned ix, unsigned len, unsigned val) +{ + int l=len; + while (--l>=0) + { + Set(ix++,val&1); + val>>=1; + } +} + +unsigned paged_bitmap::Bits(unsigned ix, unsigned len) const +{ + int l=len; + unsigned val=0; + unsigned bit=0; + while (--l>=0) + val |= (*this)[ix++]< iNbits) + return false; + for (;;) + { + if ((*this)[ix] != bit) + return false; + if (++ix==i2) + return true; + } +} + +int paged_bitmap::Find(unsigned start, unsigned bit) const +{ + if (start 0) + { + if (aPagePower < MINPAGEPOWER) + aPagePower = MINPAGEPOWER; + } + else aPagePower = 31; + + iPageThreshold = aPagePower; + /*------------------------------------------------------------- + * Initialize page bitmap + *-------------------------------------------------------------*/ + iPageMap.Init((unsigned char*)&iBitMapBuffer, MAXSMALLPAGEBITS, 0); +} + +void* RHybridHeap::PagedAllocate(unsigned size) +{ + TInt nbytes = Ceiling(size, iPageSize); + void* p = Map(0, nbytes); + if (!p) + return 0; + if (!PagedSetSize(p, nbytes)) + { + Unmap(p, nbytes); + return 0; + } + return p; +} + +void* RHybridHeap::PagedReallocate(void* p, unsigned size, TInt mode) +{ + + HEAP_ASSERT(Ceiling(p, iPageSize) == p); + unsigned nbytes = Ceiling(size, iPageSize); + + unsigned osize = PagedSize(p); + if ( nbytes == 0 ) // Special case to handle shrinking below min page threshold + nbytes = Min((1 << MINPAGEPOWER), osize); + + if (osize == nbytes) + return p; + + if (nbytes < osize) + { // shrink in place, unmap final pages and rewrite the pagemap + Unmap(Offset(p, nbytes), osize-nbytes); + // zap old code and then write new code (will not fail) + PagedZapSize(p, osize); + + TBool check = PagedSetSize(p, nbytes); + __ASSERT_ALWAYS(check, HEAP_PANIC(ETHeapBadCellAddress)); + + return p; + } + + // nbytes > osize + // try and extend current region first + + void* newp = Map(Offset(p, osize), nbytes-osize); + if (newp) + { // In place growth. Possibility that pagemap may have to grow AND then fails + if (!PagedSetSize(p, nbytes)) + { // must release extra mapping + Unmap(Offset(p, osize), nbytes-osize); + return 0; + } + // if successful, the new length code will have overwritten the old one (it is at least as long) + return p; + } + + // fallback to allocate/copy/free + if (mode & ENeverMove) + return 0; // not allowed to move cell + + newp = PagedAllocate(nbytes); + if (!newp) + return 0; + memcpy(newp, p, osize); + PagedFree(p); + return newp; +} + +void RHybridHeap::PagedFree(void* p) +{ + HEAP_ASSERT(Ceiling(p, iPageSize) == p); + + + unsigned size = PagedSize(p); + + PagedZapSize(p, size); // clear page map + Unmap(p, size); +} + +void RHybridHeap::PagedInfo(struct HeapInfo* i, SWalkInfo* wi) const +{ + for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;) + { + int npage = PagedDecode(ix); + // Introduce paged buffer to the walk function + TAny* bfr = Bitmap2addr(ix); + int len = npage << PAGESHIFT; + if ( len > iPageSize ) + { // If buffer is not larger than one page it must be a slab page mapped into bitmap + i->iAllocBytes += len; + ++i->iAllocN; + Walk(wi, bfr, len, EGoodAllocatedCell, EPageAllocator); + } + ix += (npage<<1); + } +} + +void RHybridHeap::ResetBitmap() +/*--------------------------------------------------------- + * Go through paged_bitmap and unmap all buffers to system + * This method is called from RHybridHeap::Reset() to unmap all page + * allocated - and slab pages which are stored in bitmap, too + *---------------------------------------------------------*/ +{ + unsigned iNbits = iPageMap.Size(); + if ( iNbits ) + { + for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;) + { + int npage = PagedDecode(ix); + void* p = Bitmap2addr(ix); + unsigned size = PagedSize(p); + PagedZapSize(p, size); // clear page map + Unmap(p, size); + ix += (npage<<1); + } + if ( (TInt)iNbits > MAXSMALLPAGEBITS ) + { + // unmap page reserved for enlarged bitmap + Unmap(iPageMap.Addr(), (iNbits >> 3) ); + } + } +} + +TBool RHybridHeap::CheckBitmap(void* aBfr, TInt aSize, TUint32& aDummy, TInt& aNPages) +/*--------------------------------------------------------- + * If aBfr = NULL + * Go through paged_bitmap and unmap all buffers to system + * and assure that by reading the first word of each page of aBfr + * that aBfr is still accessible + * else + * Assure that specified buffer is mapped with correct length in + * page map + *---------------------------------------------------------*/ +{ + TBool ret; + if ( aBfr ) + { + __ASSERT_ALWAYS((Ceiling(aBfr, iPageSize) == aBfr), HEAP_PANIC(ETHeapBadCellAddress)); + ret = ( aSize == (TInt)PagedSize(aBfr)); + } + else + { + ret = ETrue; + unsigned iNbits = iPageMap.Size(); + if ( iNbits ) + { + TInt npage; + aNPages = 0; + for (int ix = 0;(ix = iPageMap.Find(ix,1)) >= 0;) + { + npage = PagedDecode(ix); + aNPages += npage; + void* p = Bitmap2addr(ix); + __ASSERT_ALWAYS((Ceiling(p, iPageSize) == p), HEAP_PANIC(ETHeapBadCellAddress)); + unsigned s = PagedSize(p); + __ASSERT_ALWAYS((Ceiling(s, iPageSize) == s), HEAP_PANIC(ETHeapBadCellAddress)); + while ( s ) + { + aDummy += *(TUint32*)((TUint8*)p + (s-iPageSize)); + s -= iPageSize; + } + ix += (npage<<1); + } + if ( (TInt)iNbits > MAXSMALLPAGEBITS ) + { + // add enlarged bitmap page(s) to total page count + npage = (iNbits >> 3); + __ASSERT_ALWAYS((Ceiling(npage, iPageSize) == npage), HEAP_PANIC(ETHeapBadCellAddress)); + aNPages += (npage / iPageSize); + } + } + } + + return ret; +} + + +// The paged allocations are tracked in a bitmap which has 2 bits per page +// this allows us to store allocations as small as 4KB +// The presence and size of an allocation is encoded as follows: +// let N = number of pages in the allocation, then +// 10 : N = 1 // 4KB +// 110n : N = 2 + n // 8-12KB +// 1110nnnn : N = nnnn // 16-60KB +// 1111n[18] : N = n[18] // 64KB-1GB + +const struct etab { unsigned char offset, len, codelen, code;} encode_table[] = +{ + {1,2,2,0x1}, + {2,4,3,0x3}, + {0,8,4,0x7}, + {0,22,4,0xf} +}; + +// Return code length for specified allocation Size(assumed to be aligned to pages) +inline unsigned paged_codelen(unsigned size, unsigned pagesz) +{ + HEAP_ASSERT(size == Ceiling(size, pagesz)); + + if (size == pagesz) + return 2; + else if (size < 4*pagesz) + return 4; + else if (size < 16*pagesz) + return 8; + else + return 22; +} + +inline const etab& paged_coding(unsigned npage) +{ + if (npage < 4) + return encode_table[npage>>1]; + else if (npage < 16) + return encode_table[2]; + else + return encode_table[3]; +} + +bool RHybridHeap::PagedEncode(unsigned pos, unsigned npage) +{ + const etab& e = paged_coding(npage); + if (pos + e.len > iPageMap.Size()) + { + // need to grow the page bitmap to fit the cell length into the map + // if we outgrow original bitmap buffer in RHybridHeap metadata, then just get enough pages to cover the full space: + // * initial 68 byte bitmap mapped (68*8*4kB):2 = 1,1MB + // * 4KB can Map(4096*8*4kB):2 = 64MB + unsigned maxsize = Ceiling(iMaxLength, iPageSize); + unsigned mapbits = maxsize >> (PAGESHIFT-1); + maxsize = Ceiling(mapbits>>3, iPageSize); + void* newb = Map(0, maxsize); + if (!newb) + return false; + + unsigned char* oldb = iPageMap.Addr(); + iPageMap.Init((unsigned char*)newb, (maxsize<<3), 0); + memcpy(newb, oldb, Ceiling(MAXSMALLPAGEBITS,8)>>3); + } + // encode the allocation block size into the bitmap, starting at the bit for the start page + unsigned bits = e.code; + bits |= (npage - e.offset) << e.codelen; + iPageMap.Set(pos, e.len, bits); + return true; +} + +unsigned RHybridHeap::PagedDecode(unsigned pos) const +{ + __ASSERT_ALWAYS(pos + 2 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress)); + + unsigned bits = iPageMap.Bits(pos,2); + __ASSERT_ALWAYS(bits & 1, HEAP_PANIC(ETHeapBadCellAddress)); + bits >>= 1; + if (bits == 0) + return 1; + __ASSERT_ALWAYS(pos + 4 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress)); + bits = iPageMap.Bits(pos+2,2); + if ((bits & 1) == 0) + return 2 + (bits>>1); + else if ((bits>>1) == 0) + { + __ASSERT_ALWAYS(pos + 8 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress)); + return iPageMap.Bits(pos+4, 4); + } + else + { + __ASSERT_ALWAYS(pos + 22 <= iPageMap.Size(), HEAP_PANIC(ETHeapBadCellAddress)); + return iPageMap.Bits(pos+4, 18); + } +} + +inline void RHybridHeap::PagedZapSize(void* p, unsigned size) +{iPageMap.Setn(PtrDiff(p, iMemBase) >> (PAGESHIFT-1), paged_codelen(size, iPageSize) ,0);} + +inline unsigned RHybridHeap::PagedSize(void* p) const + { return PagedDecode(PtrDiff(p, iMemBase) >> (PAGESHIFT-1)) << PAGESHIFT; } + +inline bool RHybridHeap::PagedSetSize(void* p, unsigned size) +{ return PagedEncode(PtrDiff(p, iMemBase) >> (PAGESHIFT-1), size >> PAGESHIFT); } + +inline void* RHybridHeap::Bitmap2addr(unsigned pos) const + { return iMemBase + (1 << (PAGESHIFT-1))*pos; } + + +#ifndef QT_SYMBIAN4_ALLOCATOR_UNWANTED_CODE +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +/** +Constructor where minimum and maximum length of the heap can be defined. +It defaults the chunk heap to be created to have use a new local chunk, +to have a grow by value of KMinHeapGrowBy, to be unaligned, not to be +single threaded and not to have any mode flags set. + +@param aMinLength The minimum length of the heap to be created. +@param aMaxLength The maximum length to which the heap to be created can grow. + If the supplied value is less than a page size, then it + is discarded and the page size is used instead. +*/ +EXPORT_C TChunkHeapCreateInfo::TChunkHeapCreateInfo(TInt aMinLength, TInt aMaxLength) : + iVersionNumber(EVersion0), iMinLength(aMinLength), iMaxLength(aMaxLength), +iAlign(0), iGrowBy(1), iSingleThread(EFalse), +iOffset(0), iPaging(EUnspecified), iMode(0), iName(NULL) +{ +} + + +/** +Sets the chunk heap to create a new chunk with the specified name. + +This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or +TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. + +@param aName The name to be given to the chunk heap to be created +If NULL, the function constructs a local chunk to host the heap. +If not NULL, a pointer to a descriptor containing the name to be +assigned to the global chunk hosting the heap. +*/ +EXPORT_C void TChunkHeapCreateInfo::SetCreateChunk(const TDesC* aName) +{ + iName = (TDesC*)aName; + iChunk.SetHandle(KNullHandle); +} + + +/** +Sets the chunk heap to be created to use the chunk specified. + +This overriddes any previous call to TChunkHeapCreateInfo::SetNewChunkHeap() or +TChunkHeapCreateInfo::SetExistingChunkHeap() for this TChunkHeapCreateInfo object. + +@param aChunk A handle to the chunk to use for the heap. +*/ +EXPORT_C void TChunkHeapCreateInfo::SetUseChunk(const RChunk aChunk) +{ + iName = NULL; + iChunk = aChunk; +} + +EXPORT_C RHeap* UserHeap::FixedHeap(TAny* aBase, TInt aMaxLength, TInt aAlign, TBool aSingleThread) +/** +Creates a fixed length heap at a specified location. + +On successful return from this function, the heap is ready to use. This assumes that +the memory pointed to by aBase is mapped and able to be used. You must ensure that you +pass in a large enough value for aMaxLength. Passing in a value that is too small to +hold the metadata for the heap (~1 KB) will result in the size being rounded up and the +heap thereby running over the end of the memory assigned to it. But then if you were to +pass in such as small value then you would not be able to do any allocations from the +heap anyway. Moral of the story: Use a sensible value for aMaxLength! + +@param aBase A pointer to the location where the heap is to be constructed. +@param aMaxLength The maximum length in bytes to which the heap can grow. If the + supplied value is too small to hold the heap's metadata, it + will be increased. +@param aAlign From Symbian^4 onwards, this value is ignored but EABI 8 + byte alignment is guaranteed for all allocations 8 bytes or + more in size. 4 byte allocations will be aligned to a 4 + byte boundary. Best to pass in zero. +@param aSingleThread EFalse if the heap is to be accessed from multiple threads. + This will cause internal locks to be created, guaranteeing + thread safety. + +@return A pointer to the new heap, or NULL if the heap could not be created. + +@panic USER 56 if aMaxLength is negative. +*/ +{ + __ASSERT_ALWAYS( aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative)); + if ( aMaxLength < (TInt)sizeof(RHybridHeap) ) + aMaxLength = sizeof(RHybridHeap); + + RHybridHeap* h = new(aBase) RHybridHeap(aMaxLength, aAlign, aSingleThread); + + if (!aSingleThread) + { + TInt r = h->iLock.CreateLocal(); + if (r!=KErrNone) + return NULL; // No need to delete the RHybridHeap instance as the new above is only a placement new + h->iHandles = (TInt*)&h->iLock; + h->iHandleCount = 1; + } + return h; +} + +/** +Creates a chunk heap of the type specified by the parameter aCreateInfo. + +@param aCreateInfo A reference to a TChunkHeapCreateInfo object specifying the +type of chunk heap to create. + +@return A pointer to the new heap or NULL if the heap could not be created. + +@panic USER 41 if the heap's specified minimum length is greater than the specified maximum length. +@panic USER 55 if the heap's specified minimum length is negative. +@panic USER 172 if the heap's specified alignment is not a power of 2 or is less than the size of a TAny*. +*/ +EXPORT_C RHeap* UserHeap::ChunkHeap(const TChunkHeapCreateInfo& aCreateInfo) +{ + // aCreateInfo must have been configured to use a new chunk or an exiting chunk. + __ASSERT_ALWAYS(!(aCreateInfo.iMode & (TUint32)~EChunkHeapMask), ::Panic(EHeapCreateInvalidMode)); + RHeap* h = NULL; + + if (aCreateInfo.iChunk.Handle() == KNullHandle) + { + // A new chunk is to be created for this heap. + + __ASSERT_ALWAYS(aCreateInfo.iMinLength >= 0, ::Panic(ETHeapMinLengthNegative)); + __ASSERT_ALWAYS(aCreateInfo.iMaxLength >= aCreateInfo.iMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); + + TInt maxLength = aCreateInfo.iMaxLength; + TInt page_size; + GET_PAGE_SIZE(page_size); + + if (maxLength < page_size) + maxLength = page_size; + + TChunkCreateInfo chunkInfo; +#if USE_HYBRID_HEAP + if ( aCreateInfo.iOffset ) + chunkInfo.SetNormal(0, maxLength); // Create DL only heap + else + { + maxLength = 2*maxLength; + chunkInfo.SetDisconnected(0, 0, maxLength); // Create hybrid heap + } +#else + chunkInfo.SetNormal(0, maxLength); // Create DL only heap +#endif + chunkInfo.SetOwner((aCreateInfo.iSingleThread)? EOwnerThread : EOwnerProcess); + if (aCreateInfo.iName) + chunkInfo.SetGlobal(*aCreateInfo.iName); + // Set the paging attributes of the chunk. + if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EPaged) + chunkInfo.SetPaging(TChunkCreateInfo::EPaged); + if (aCreateInfo.iPaging == TChunkHeapCreateInfo::EUnpaged) + chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); + // Create the chunk. + RChunk chunk; + if (chunk.Create(chunkInfo) != KErrNone) + return NULL; + // Create the heap using the new chunk. + TUint mode = aCreateInfo.iMode | EChunkHeapDuplicate; // Must duplicate the handle. + h = OffsetChunkHeap(chunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, + aCreateInfo.iGrowBy, maxLength, aCreateInfo.iAlign, + aCreateInfo.iSingleThread, mode); + chunk.Close(); + } + else + { + h = OffsetChunkHeap(aCreateInfo.iChunk, aCreateInfo.iMinLength, aCreateInfo.iOffset, + aCreateInfo.iGrowBy, aCreateInfo.iMaxLength, aCreateInfo.iAlign, + aCreateInfo.iSingleThread, aCreateInfo.iMode); + } + return h; +} + + + +EXPORT_C RHeap* UserHeap::ChunkHeap(const TDesC* aName, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread) +/** +Creates a heap in a local or global chunk. + +The chunk hosting the heap can be local or global. + +A local chunk is one which is private to the process creating it and is not +intended for access by other user processes. A global chunk is one which is +visible to all processes. + +The hosting chunk is local, if the pointer aName is NULL, otherwise the +hosting chunk is global and the descriptor *aName is assumed to contain +the name to be assigned to it. + +Ownership of the host chunk is vested in the current process. + +A minimum and a maximum size for the heap can be specified. On successful +return from this function, the size of the heap is at least aMinLength. +If subsequent requests for allocation of memory from the heap cannot be +satisfied by compressing the heap, the size of the heap is extended in +increments of aGrowBy until the request can be satisfied. Attempts to extend +the heap causes the size of the host chunk to be adjusted. + +Note that the size of the heap cannot be adjusted by more than aMaxLength. + +@param aName If NULL, the function constructs a local chunk to host + the heap. If not NULL, a pointer to a descriptor containing + the name to be assigned to the global chunk hosting the heap. +@param aMinLength The minimum length of the heap in bytes. This will be + rounded up to the nearest page size by the allocator. +@param aMaxLength The maximum length in bytes to which the heap can grow. This + will be rounded up to the nearest page size by the allocator. +@param aGrowBy The number of bytes by which the heap will grow when more + memory is required. This will be rounded up to the nearest + page size by the allocator. If a value is not explicitly + specified, the page size is taken by default. +@param aAlign From Symbian^4 onwards, this value is ignored but EABI 8 + byte alignment is guaranteed for all allocations 8 bytes or + more in size. 4 byte allocations will be aligned to a 4 + byte boundary. Best to pass in zero. +@param aSingleThread EFalse if the heap is to be accessed from multiple threads. + This will cause internal locks to be created, guaranteeing + thread safety. + +@return A pointer to the new heap or NULL if the heap could not be created. + +@panic USER 41 if aMaxLength is < aMinLength. +@panic USER 55 if aMinLength is negative. +@panic USER 56 if aMaxLength is negative. +*/ + { + TInt page_size; + GET_PAGE_SIZE(page_size); + TInt minLength = _ALIGN_UP(aMinLength, page_size); + TInt maxLength = Max(aMaxLength, minLength); + + TChunkHeapCreateInfo createInfo(minLength, maxLength); + createInfo.SetCreateChunk(aName); + createInfo.SetGrowBy(aGrowBy); + createInfo.SetAlignment(aAlign); + createInfo.SetSingleThread(aSingleThread); + + return ChunkHeap(createInfo); + } +#endif // QT_SYMBIAN4_ALLOCATOR_UNWANTED_CODE + +EXPORT_C RHeap* UserHeap::ChunkHeap(RChunk aChunk, TInt aMinLength, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) +/** +Creates a heap in an existing chunk. + +This function is intended to be used to create a heap in a user writable code +chunk as created by a call to RChunk::CreateLocalCode(). This type of heap can +be used to hold code fragments from a JIT compiler. + +@param aChunk The chunk that will host the heap. +@param aMinLength The minimum length of the heap in bytes. This will be + rounded up to the nearest page size by the allocator. +@param aGrowBy The number of bytes by which the heap will grow when more + memory is required. This will be rounded up to the nearest + page size by the allocator. If a value is not explicitly + specified, the page size is taken by default. +@param aMaxLength The maximum length in bytes to which the heap can grow. This + will be rounded up to the nearest page size by the allocator. + If 0 is passed in, the maximum lengt of the chunk is used. +@param aAlign From Symbian^4 onwards, this value is ignored but EABI 8 + byte alignment is guaranteed for all allocations 8 bytes or + more in size. 4 byte allocations will be aligned to a 4 + byte boundary. Best to pass in zero. +@param aSingleThread EFalse if the heap is to be accessed from multiple threads. + This will cause internal locks to be created, guaranteeing + thread safety. +@param aMode Flags controlling the heap creation. See RAllocator::TFlags. + +@return A pointer to the new heap or NULL if the heap could not be created. + +@see UserHeap::OffsetChunkHeap() +*/ + { + return OffsetChunkHeap(aChunk, aMinLength, 0, aGrowBy, aMaxLength, aAlign, aSingleThread, aMode); + } + +EXPORT_C RHeap* UserHeap::OffsetChunkHeap(RChunk aChunk, TInt aMinLength, TInt aOffset, TInt aGrowBy, TInt aMaxLength, TInt aAlign, TBool aSingleThread, TUint32 aMode) +/** +Creates a heap in an existing chunk, offset from the beginning of the chunk. + +This function is intended to be used to create a heap using a chunk which has +some of its memory already used, at the start of that that chunk. The maximum +length to which the heap can grow is the maximum size of the chunk, minus the +data at the start of the chunk. + +The offset at which to create the heap is passed in as the aOffset parameter. +Legacy heap implementations always respected the aOffset value, however more +modern heap implementations are more sophisticated and cannot necessarily respect +this value. Therefore, if possible, you should always use an aOffset of 0 unless +you have a very explicit requirement for using a non zero value. Using a non zero +value will result in a less efficient heap algorithm being used in order to respect +the offset. + +Another issue to consider when using this function is the type of the chunk passed +in. In order for the most efficient heap algorithms to be used, the chunk passed +in should always be a disconnected chunk. Passing in a non disconnected chunk will +again result in a less efficient heap algorithm being used. + +Finally, another requirement for the most efficient heap algorithms to be used is +for the heap to be able to expand. Therefore, unless you have a specific reason to +do so, always specify aMaxLength > aMinLength. + +So, if possible, use aOffset == zero, aMaxLength > aMinLength and a disconnected +chunk for best results! + +@param aChunk The chunk that will host the heap. +@param aMinLength The minimum length of the heap in bytes. This will be + rounded up to the nearest page size by the allocator. +@param aOffset The offset in bytes from the start of the chunk at which to + create the heap. If used (and it shouldn't really be!) + then it will be rounded up to a multiple of 8, to respect + EABI 8 byte alignment requirements. +@param aGrowBy The number of bytes by which the heap will grow when more + memory is required. This will be rounded up to the nearest + page size by the allocator. If a value is not explicitly + specified, the page size is taken by default. +@param aMaxLength The maximum length in bytes to which the heap can grow. This + will be rounded up to the nearest page size by the allocator. + If 0 is passed in, the maximum length of the chunk is used. +@param aAlign From Symbian^4 onwards, this value is ignored but EABI 8 + byte alignment is guaranteed for all allocations 8 bytes or + more in size. 4 byte allocations will be aligned to a 4 + byte boundary. Best to pass in zero. +@param aSingleThread EFalse if the heap is to be accessed from multiple threads. + This will cause internal locks to be created, guaranteeing + thread safety. +@param aMode Flags controlling the heap creation. See RAllocator::TFlags. + +@return A pointer to the new heap or NULL if the heap could not be created. + +@panic USER 41 if aMaxLength is < aMinLength. +@panic USER 55 if aMinLength is negative. +@panic USER 56 if aMaxLength is negative. +@panic USER 168 if aOffset is negative. +*/ + { + TBool dlOnly = EFalse; + TInt pageSize; + GET_PAGE_SIZE(pageSize); + TInt align = RHybridHeap::ECellAlignment; // Always use EABI 8 byte alignment + + __ASSERT_ALWAYS(aMinLength>=0, ::Panic(ETHeapMinLengthNegative)); + __ASSERT_ALWAYS(aMaxLength>=0, ::Panic(ETHeapMaxLengthNegative)); + + if ( aMaxLength > 0 ) + __ASSERT_ALWAYS(aMaxLength>=aMinLength, ::Panic(ETHeapCreateMaxLessThanMin)); + + // Stick to EABI alignment for the start offset, if any + aOffset = _ALIGN_UP(aOffset, align); + + // Using an aOffset > 0 means that we can't use the hybrid allocator and have to revert to Doug Lea only + if (aOffset > 0) + dlOnly = ETrue; + + // Ensure that the minimum length is enough to hold the RHybridHeap object itself + TInt minCell = _ALIGN_UP(Max((TInt)RHybridHeap::EAllocCellSize, (TInt)RHybridHeap::EFreeCellSize), align); + TInt hybridHeapSize = (sizeof(RHybridHeap) + minCell); + if (aMinLength < hybridHeapSize) + aMinLength = hybridHeapSize; + + // Round the minimum length up to a multiple of the page size, taking into account that the + // offset takes up a part of the chunk's memory + aMinLength = _ALIGN_UP((aMinLength + aOffset), pageSize); + + // If aMaxLength is 0 then use the entire chunk + TInt chunkSize = aChunk.MaxSize(); + if (aMaxLength == 0) + { + aMaxLength = chunkSize; + } + // Otherwise round the maximum length up to a multiple of the page size, taking into account that + // the offset takes up a part of the chunk's memory. We also clip the maximum length to the chunk + // size, so the user may get a little less than requested if the chunk size is not large enough + else + { + aMaxLength = _ALIGN_UP((aMaxLength + aOffset), pageSize); + if (aMaxLength > chunkSize) + aMaxLength = chunkSize; + } + + // If the rounded up values don't make sense then a crazy aMinLength or aOffset must have been passed + // in, so fail the heap creation + if (aMinLength > aMaxLength) + return NULL; + + // Adding the offset into the minimum and maximum length was only necessary for ensuring a good fit of + // the heap into the chunk. Re-adjust them now back to non offset relative sizes + aMinLength -= aOffset; + aMaxLength -= aOffset; + + // If we are still creating the hybrid allocator (call parameter + // aOffset is 0 and aMaxLength > aMinLength), we must reduce heap + // aMaxLength size to the value aMaxLength/2 and set the aOffset to point in the middle of chunk. + TInt offset = aOffset; + TInt maxLength = aMaxLength; + if (!dlOnly && (aMaxLength > aMinLength)) + maxLength = offset = _ALIGN_UP(aMaxLength >> 1, pageSize); + + // Try to use commit to map aMinLength physical memory for the heap, taking into account the offset. If + // the operation fails, suppose that the chunk is not a disconnected heap and try to map physical memory + // with adjust. In this case, we also can't use the hybrid allocator and have to revert to Doug Lea only + TBool useAdjust = EFalse; + TInt r = aChunk.Commit(offset, aMinLength); + if (r == KErrGeneral) + { + dlOnly = useAdjust = ETrue; + r = aChunk.Adjust(aMinLength); + if (r != KErrNone) + return NULL; + } + else if (r == KErrNone) + { + // We have a disconnected chunk reset aOffset and aMaxlength + aOffset = offset; + aMaxLength = maxLength; + } + + else + return NULL; + + // Parameters have been mostly verified and we know whether to use the hybrid allocator or Doug Lea only. The + // constructor for the hybrid heap will automatically drop back to Doug Lea if it determines that aMinLength + // == aMaxLength, so no need to worry about that requirement here. The user specified alignment is not used but + // is passed in so that it can be sanity checked in case the user is doing something totally crazy with it + RHybridHeap* h = new (aChunk.Base() + aOffset) RHybridHeap(aChunk.Handle(), aOffset, aMinLength, aMaxLength, + aGrowBy, aAlign, aSingleThread, dlOnly, useAdjust); + + if (h->ConstructLock(aMode) != KErrNone) + return NULL; + + // Return the heap address + return h; + } + +#define UserTestDebugMaskBit(bit) (TBool)(UserSvr::DebugMask(bit>>5) & (1<<(bit&31))) + +_LIT(KLitDollarHeap,"$HEAP"); +EXPORT_C TInt UserHeap::CreateThreadHeap(SStdEpocThreadCreateInfo& aInfo, RHeap*& aHeap, TInt aAlign, TBool aSingleThread) +/** +@internalComponent +*/ +// +// Create a user-side heap +// +{ + TInt page_size; + GET_PAGE_SIZE(page_size); + TInt minLength = _ALIGN_UP(aInfo.iHeapInitialSize, page_size); + TInt maxLength = Max(aInfo.iHeapMaxSize, minLength); +#ifdef ENABLE_BTRACE + if (UserTestDebugMaskBit(96)) // 96 == KUSERHEAPTRACE in nk_trace.h + aInfo.iFlags |= ETraceHeapAllocs; +#endif // ENABLE_BTRACE + // Create the thread's heap chunk. + RChunk c; +#ifndef NO_NAMED_LOCAL_CHUNKS + TChunkCreateInfo createInfo; + + createInfo.SetThreadHeap(0, maxLength, KLitDollarHeap()); // Initialise with no memory committed. +#if USE_HYBRID_HEAP + // + // Create disconnected chunk for hybrid heap with double max length value + // + maxLength = 2*maxLength; + createInfo.SetDisconnected(0, 0, maxLength); +#endif +#ifdef SYMBIAN_WRITABLE_DATA_PAGING + // Set the paging policy of the heap chunk based on the thread's paging policy. + TUint pagingflags = aInfo.iFlags & EThreadCreateFlagPagingMask; + switch (pagingflags) + { + case EThreadCreateFlagPaged: + createInfo.SetPaging(TChunkCreateInfo::EPaged); + break; + case EThreadCreateFlagUnpaged: + createInfo.SetPaging(TChunkCreateInfo::EUnpaged); + break; + case EThreadCreateFlagPagingUnspec: + // Leave the chunk paging policy unspecified so the process's + // paging policy is used. + break; + } +#endif // SYMBIAN_WRITABLE_DATA_PAGING + + TInt r = c.Create(createInfo); +#else + TInt r = c.CreateDisconnectedLocal(0, 0, maxLength * 2); +#endif + if (r!=KErrNone) + return r; + + aHeap = ChunkHeap(c, minLength, page_size, maxLength, aAlign, aSingleThread, EChunkHeapSwitchTo|EChunkHeapDuplicate); + c.Close(); + + if ( !aHeap ) + return KErrNoMemory; + +#ifdef ENABLE_BTRACE + if (aInfo.iFlags & ETraceHeapAllocs) + { + aHeap->iFlags |= RHeap::ETraceAllocs; + BTraceContext8(BTrace::EHeap, BTrace::EHeapCreate,(TUint32)aHeap, RHybridHeap::EAllocCellSize); + TInt chunkId = ((RHandleBase&)((RHybridHeap*)aHeap)->iChunkHandle).BTraceId(); + BTraceContext8(BTrace::EHeap, BTrace::EHeapChunkCreate, (TUint32)aHeap, chunkId); + } + if (aInfo.iFlags & EMonitorHeapMemory) + aHeap->iFlags |= RHeap::EMonitorMemory; +#endif // ENABLE_BTRACE + + return KErrNone; +} + +#endif // __KERNEL_MODE__ + +#endif /* QT_USE_NEW_SYMBIAN_ALLOCATOR */ diff --git a/src/corelib/arch/symbian/heap_hybrid_p.h b/src/corelib/arch/symbian/heap_hybrid_p.h new file mode 100644 index 0000000000..1767fc1344 --- /dev/null +++ b/src/corelib/arch/symbian/heap_hybrid_p.h @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __HEAP_HYBRID_H__ +#define __HEAP_HYBRID_H__ + +#include + +#ifdef __WINS__ +#define USE_HYBRID_HEAP 0 +#else +#define USE_HYBRID_HEAP 1 +#endif + +// This stuff is all temporary in order to prevent having to include dla.h from heap_hybrid.h, which causes +// problems due to its definition of size_t (and possibly other types). This is unfortunate but we cannot +// pollute the namespace with these types or it will cause problems with Open C and other POSIX compatibility +// efforts in Symbian + +#define NSMALLBINS (32U) +#define NTREEBINS (32U) + +#ifndef MALLOC_ALIGNMENT + #define MALLOC_ALIGNMENT ((TUint)8U) +#endif /* MALLOC_ALIGNMENT */ + +#define CHUNK_OVERHEAD (sizeof(TUint)) + +typedef unsigned int bindex_t; +typedef unsigned int binmap_t; +typedef struct malloc_chunk* mchunkptr; +typedef struct malloc_segment msegment; +typedef struct malloc_state* mstate; +typedef struct malloc_tree_chunk* tbinptr; +typedef struct malloc_tree_chunk* tchunkptr; + +struct malloc_segment { + TUint8* iBase; /* base address */ + TUint iSize; /* allocated size */ +}; + +struct malloc_state { + binmap_t iSmallMap; + binmap_t iTreeMap; + TUint iDvSize; + TUint iTopSize; + mchunkptr iDv; + mchunkptr iTop; + TUint iTrimCheck; + mchunkptr iSmallBins[(NSMALLBINS+1)*2]; + tbinptr iTreeBins[NTREEBINS]; + msegment iSeg; + }; + +class RHybridHeap : public RHeap + { + +public: + // declarations copied from Symbian^4 RAllocator and RHeap + typedef void (*TWalkFunc)(TAny*, RHeap::TCellType, TAny*, TInt); + enum TFlags {ESingleThreaded=1, EFixedSize=2, ETraceAllocs=4, EMonitorMemory=8,}; + enum TAllocDebugOp + { + ECount, EMarkStart, EMarkEnd, ECheck, ESetFail, ECopyDebugInfo, ESetBurstFail, EGetFail, + EGetSize=48, EGetMaxLength, EGetBase, EAlignInteger, EAlignAddr + }; + enum TDebugOp { EWalk = 128, EHybridHeap }; + enum THybridAllocFail + { + ERandom, ETrueRandom, EDeterministic, EHybridNone, EFailNext, EReset, EBurstRandom, + EBurstTrueRandom, EBurstDeterministic, EBurstFailNext, ECheckFailure, + }; + enum { EDebugHdrSize = sizeof(SDebugCell) }; +#ifndef SYMBIAN_ENABLE_SPLIT_HEADERS + struct SRAllocatorBurstFail {TInt iBurst; TInt iRate; TInt iUnused[2];}; +#endif + + struct HeapInfo + { + unsigned iFootprint; + unsigned iMaxSize; + unsigned iAllocBytes; + unsigned iAllocN; + unsigned iFreeBytes; + unsigned iFreeN; + }; + + struct SHeapCellInfo { RHybridHeap* iHeap; TInt iTotalAlloc; TInt iTotalAllocSize; TInt iTotalFree; TInt iLevelAlloc; SDebugCell* iStranded; }; + + + /** + @internalComponent + */ + enum TAllocatorType + {ESlabAllocator, EDougLeaAllocator, EPageAllocator, EFullSlab=0x80, EPartialFullSlab=0x40, EEmptySlab=0x20, ESlabSpare=0x10, ESlabMask=0xf0}; + + + /** + @internalComponent + */ + struct SWalkInfo { + /** + Walk function address shall be called + */ + TWalkFunc iFunction; + + /** + The first parameter for callback function + */ + TAny* iParam; + /** + Pointer to RHybridHeap object + */ + RHybridHeap* iHeap; + }; + + /** + @internalComponent + */ + struct SConfig { + /** + Required slab configuration ( bit 0=4, bit 1=8 .. + bit 13 = 56) + */ + TUint32 iSlabBits; + /** + Delayed slab threshold in bytes (0 = no threshold) + */ + TInt iDelayedSlabThreshold; + /** + 2^n is smallest size allocated in paged allocator (14-31 = 16 Kb --> ) + */ + TInt iPagePower; + + }; + + /** + @internalComponent + + This structure is used by test code for configuring the allocators and obtaining information + from them in order to ensure they are behaving as required. This is internal test specific + code and is liable to be changed without warning at any time. You should under no circumstances + be using it! + */ + struct STestCommand + { + TInt iCommand; // The test related command to be executed + + union + { + SConfig iConfig; // Configuration used by test code only + TAny* iData; // Extra supporting data for the test command + }; + }; + + /** + @internalComponent + + Commands used by test code for configuring the allocators and obtaining information them them + */ + enum TTestCommand { EGetConfig, ESetConfig, EHeapMetaData, ETestData }; + + virtual TAny* Alloc(TInt aSize); + virtual void Free(TAny* aPtr); + virtual TAny* ReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0); + virtual TInt AllocLen(const TAny* aCell) const; +#ifndef __KERNEL_MODE__ + virtual TInt Compress(); + virtual void Reset(); + virtual TInt AllocSize(TInt& aTotalAllocSize) const; + virtual TInt Available(TInt& aBiggestBlock) const; +#endif + virtual TInt DebugFunction(TInt aFunc, TAny* a1=NULL, TAny* a2=NULL); +protected: + virtual TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1); + +public: + TAny* operator new(TUint aSize, TAny* aBase) __NO_THROW; + void operator delete(TAny*, TAny*); + +private: + TInt DoCountAllocFree(TInt& aFree); + TInt DoCheckHeap(SCheckInfo* aInfo); + void DoMarkStart(); + TUint32 DoMarkEnd(TInt aExpected); + void DoSetAllocFail(TAllocFail aType, TInt aRate); + TBool CheckForSimulatedAllocFail(); + void DoSetAllocFail(TAllocFail aType, TInt aRate, TUint aBurst); + + void Lock() const; + void Unlock() const; + TInt ChunkHandle() const; + + RHybridHeap(TInt aChunkHandle, TInt aOffset, TInt aMinLength, TInt aMaxLength, TInt aGrowBy, TInt aAlign, TBool aSingleThread, TBool aDlOnly, TBool aUseAdjust); + RHybridHeap(TInt aMaxLength, TInt aAlign=0, TBool aSingleThread=ETrue); + RHybridHeap(); + + void Init(TInt aBitmapSlab, TInt aPagePower); + inline void InitBins(mstate m); + inline void InitTop(mstate m, mchunkptr p, TUint psize); + void* SysAlloc(mstate m, TUint nb); + int SysTrim(mstate m, TUint pad); + void* TmallocLarge(mstate m, TUint nb); + void* TmallocSmall(mstate m, TUint nb); + /*MACROS converted functions*/ + static inline void UnlinkFirstSmallChunk(mstate M,mchunkptr B,mchunkptr P,bindex_t& I); + static inline void InsertSmallChunk(mstate M,mchunkptr P, TUint S); + static inline void InsertChunk(mstate M,mchunkptr P,TUint S); + static inline void UnlinkLargeChunk(mstate M,tchunkptr X); + static inline void UnlinkSmallChunk(mstate M, mchunkptr P,TUint S); + static inline void UnlinkChunk(mstate M, mchunkptr P, TUint S); + static inline void ComputeTreeIndex(TUint S, bindex_t& I); + static inline void InsertLargeChunk(mstate M,tchunkptr X,TUint S); + static inline void ReplaceDv(mstate M, mchunkptr P, TUint S); + static inline void ComputeBit2idx(binmap_t X,bindex_t& I); + + void DoComputeTreeIndex(TUint S, bindex_t& I); + void DoCheckAnyChunk(mstate m, mchunkptr p); + void DoCheckTopChunk(mstate m, mchunkptr p); + void DoCheckInuseChunk(mstate m, mchunkptr p); + void DoCheckFreeChunk(mstate m, mchunkptr p); + void DoCheckMallocedChunk(mstate m, void* mem, TUint s); + void DoCheckTree(mstate m, tchunkptr t); + void DoCheckTreebin(mstate m, bindex_t i); + void DoCheckSmallbin(mstate m, bindex_t i); + TInt BinFind(mstate m, mchunkptr x); + TUint TraverseAndCheck(mstate m); + void DoCheckMallocState(mstate m); + + TInt GetInfo(struct HeapInfo* i, SWalkInfo* wi=NULL) const; + void InitDlMalloc(TUint capacity, int locked); + void* DlMalloc(TUint); + void DlFree(void*); + void* DlRealloc(void*, TUint, TInt); + TUint DlInfo(struct HeapInfo* i, SWalkInfo* wi) const; + void DoCheckCommittedSize(TInt aNPages, mstate aM); + + TAny* ReAllocImpl(TAny* aPtr, TInt aSize, TInt aMode); + void Construct(TBool aSingleThread, TBool aDLOnly, TBool aUseAdjust, TInt aAlign); +#ifndef __KERNEL_MODE__ + TInt ConstructLock(TUint32 aMode); +#endif + static void Walk(SWalkInfo* aInfo, TAny* aBfr, TInt aLth, TCellType aBfrType, TAllocatorType aAlloctorType); + static void WalkCheckCell(TAny* aPtr, TCellType aType, TAny* aCell, TInt aLen); + void* Map(void* p, TInt sz); + void Unmap(void* p,TInt sz); + +private: + TInt iMinLength; + TInt iOffset; // offset of RHeap object from chunk base + TInt iGrowBy; + TInt iMinCell; + TInt iPageSize; + + // Temporarily commented out and exported from RHeap to prevent source breaks from req417-52840. + // This will be moved with another REQ after submission and subsequent fixing of bad code + //TInt iNestingLevel; + TInt iAllocCount; + // Temporarily commented out. See comment above regarding req417-52840 source breaks + //TAllocFail iFailType; + TInt iFailRate; + TBool iFailed; + TInt iFailAllocCount; + TInt iRand; + // Temporarily commented out. See comment above regarding req417-52840 source breaks + //TAny* iTestData; + + TInt iChunkSize; + TInt iHighWaterMark; + TBool iUseAdjust; + TBool iDLOnly; + + malloc_state iGlobalMallocState; + +#ifdef __KERNEL_MODE__ + + friend class RHeapK; + +#else + + friend class UserHeap; + friend class HybridHeap; + friend class TestHybridHeap; + +private: + + static void TreeRemove(slab* s); + static void TreeInsert(slab* s,slab** r); + + enum {EOkBits = (1<<(MAXSLABSIZE>>2))-1}; + + void SlabInit(); + void SlabConfig(unsigned slabbitmap); + void* SlabAllocate(slabset& allocator); + void SlabFree(void* p); + void* AllocNewSlab(slabset& allocator); + void* AllocNewPage(slabset& allocator); + void* InitNewSlab(slabset& allocator, slab* s); + void FreeSlab(slab* s); + void FreePage(page* p); + void SlabInfo(struct HeapInfo* i, SWalkInfo* wi) const; + static void SlabFullInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi); + static void SlabPartialInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi); + static void SlabEmptyInfo(slab* s, struct HeapInfo* i, SWalkInfo* wi); + static void TreeWalk(slab* const* root, void (*f)(slab*, struct HeapInfo*, SWalkInfo*), struct HeapInfo* i, SWalkInfo* wi); + + static void WalkPartialFullSlab(SWalkInfo* aInfo, slab* aSlab, TCellType aBfrType, TInt aLth); + static void WalkFullSlab(SWalkInfo* aInfo, slab* aSlab, TCellType aBfrType, TInt aLth); + void DoCheckSlab(slab* aSlab, TAllocatorType aSlabType, TAny* aBfr=NULL); + void DoCheckSlabTrees(); + void DoCheckSlabTree(slab** aS, TBool aPartialPage); + void BuildPartialSlabBitmap(TUint32* aBitmap, slab* aSlab, TAny* aBfr=NULL); + + static inline unsigned SlabHeaderFree(unsigned h) + {return (h&0x000000ff);} + static inline unsigned SlabHeaderPagemap(unsigned h) + {return (h&0x00000f00)>>8;} + static inline unsigned SlabHeaderSize(unsigned h) + {return (h&0x0003f000)>>12;} + static inline unsigned SlabHeaderUsedm4(unsigned h) + {return (h&0x0ffc0000)>>18;} + /***paged allocator code***/ + void PagedInit(TInt aPagePower); + void* PagedAllocate(unsigned size); + void PagedFree(void* p); + void* PagedReallocate(void* p, unsigned size, TInt mode); + + bool PagedEncode(unsigned pos, unsigned npage); + unsigned PagedDecode(unsigned pos) const; + inline unsigned PagedSize(void* p) const; + inline bool PagedSetSize(void* p, unsigned size); + inline void PagedZapSize(void* p, unsigned size); + inline void* Bitmap2addr(unsigned pos) const; + void PagedInfo(struct HeapInfo* i, SWalkInfo* wi) const; + void ResetBitmap(); + TBool CheckBitmap(void* aBfr, TInt aSize, TUint32& aDummy, TInt& aNPages); + +private: + paged_bitmap iPageMap; // bitmap representing page allocator's pages + TUint8* iMemBase; // bottom of paged/slab memory (chunk base) + TUint8 iBitMapBuffer[MAXSMALLPAGEBITS>>3]; // buffer for initial page bitmap + TInt iSlabThreshold; // allocations < than this are done by the slab allocator + TInt iPageThreshold; // 2^n is smallest cell size allocated in paged allocator + TInt iSlabInitThreshold; // slab allocator will be used after chunk reaches this size + TUint32 iSlabConfigBits; // set of bits that specify which slab sizes to use + slab* iPartialPage; // partial-use page tree + slab* iFullSlab; // full slabs list (so we can find them when walking) + page* iSparePage; // cached, to avoid kernel exec calls for unmapping/remapping + TUint8 iSizeMap[(MAXSLABSIZE>>2)+1]; // index of slabset indexes based on size class + slabset iSlabAlloc[MAXSLABSIZE>>2]; // array of pointers to slabsets + +#endif // __KERNEL_MODE__ +}; + +#define HEAP_ASSERT(x) __ASSERT_DEBUG(x, HEAP_PANIC(ETHeapBadCellAddress)) + +template inline T Floor(const T addr, unsigned aln) +{return T((unsigned(addr))&~(aln-1));} +template inline T Ceiling(T addr, unsigned aln) +{return T((unsigned(addr)+(aln-1))&~(aln-1));} +template inline unsigned LowBits(T addr, unsigned aln) +{return unsigned(addr)&(aln-1);} +template inline int PtrDiff(const T1* a1, const T2* a2) +{return reinterpret_cast(a1) - reinterpret_cast(a2);} +template inline T Offset(T addr, unsigned ofs) +{return T(unsigned(addr)+ofs);} + +#endif //__HEAP_HYBRID_H__ diff --git a/src/corelib/arch/symbian/page_alloc_p.h b/src/corelib/arch/symbian/page_alloc_p.h new file mode 100644 index 0000000000..f92bd332ff --- /dev/null +++ b/src/corelib/arch/symbian/page_alloc_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __KERNEL_MODE__ + +const int MAXSMALLPAGEBITS = 68<<3; +#define MINPAGEPOWER PAGESHIFT+2 + +struct paged_bitmap +{ + public: + inline paged_bitmap() : iBase(0), iNbits(0) {} + void Init(unsigned char* p, unsigned size, unsigned bit); +// + inline unsigned char* Addr() const; + inline unsigned Size() const; +// + inline void Set(unsigned ix, unsigned bit); + inline unsigned operator[](unsigned ix) const; + bool Is(unsigned ix, unsigned len, unsigned bit) const; + void Set(unsigned ix, unsigned len, unsigned val); + void Setn(unsigned ix, unsigned len, unsigned bit); + unsigned Bits(unsigned ix, unsigned len) const; // little endian + int Find(unsigned start, unsigned bit) const; + private: + unsigned char* iBase; + unsigned iNbits; +}; + +#endif // __KERNEL_MODE__ diff --git a/src/corelib/arch/symbian/qatomic_generic_armv6.cpp b/src/corelib/arch/symbian/qatomic_generic_armv6.cpp new file mode 100644 index 0000000000..f9ce6fd154 --- /dev/null +++ b/src/corelib/arch/symbian/qatomic_generic_armv6.cpp @@ -0,0 +1,472 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +** This file implements the generic atomics interface using ARMv6 assembly +** instructions. It is more efficient than the inline versions when Qt is +** built for the THUMB instruction set, as the required instructions are +** only available in ARM state. +****************************************************************************/ + +#include + +#ifdef QT_HAVE_ARMV6 +#ifndef SYMBIAN_E32_ATOMIC_API + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +#ifdef Q_CC_RVCT +#pragma push +#pragma arm +Q_CORE_EXPORT asm +bool QBasicAtomicInt_testAndSetRelaxed(volatile int *_q_value, int expectedValue, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicInt_testAndSetAcquire(volatile int *_q_value, int expectedValue, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicInt_testAndSetRelease(volatile int *_q_value, int expectedValue, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + CODE32 + //R0 = _q_value + //R1 = expectedValue + //R2 = newValue +retry_testAndSetOrdered + LDREX r3,[r0] //r3 = *_q_value + EORS r3,r3,r1 //if (r3 == expectedValue) { + STREXEQ r3,r2,[r0] //*_q_value = newvalue, r3 = error + TEQEQ r3,#1 //if error + BEQ retry_testAndSetOrdered //then goto retry } + RSBS r0,r3,#1 //return (r3 == 0) + MOVCC r0,#0 + BX r14 +} + +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndStoreRelaxed(volatile int *_q_value, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndStoreAcquire(volatile int *_q_value, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndStoreRelease(volatile int *_q_value, int newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ + CODE32 +//R0 = _q_value +//R1 = newValue +retry_fetchAndStoreOrdered + LDREX r3,[r0] //r3 = *_q_value + STREX r2,r1,[r0] //*_q_value = newValue, r2 = error + TEQ r2,#0 //if error + BNE retry_fetchAndStoreOrdered //then goto retry + MOV r0,r3 //return r3 + BX r14 +} + +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndAddRelaxed(volatile int *_q_value, int valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndAddAcquire(volatile int *_q_value, int valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndAddRelease(volatile int *_q_value, int valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + CODE32 + //R0 = _q_value + //R1 = valueToAdd + STMDB sp!,{r12,lr} +retry_fetchAndAddOrdered + LDREX r2,[r0] //r2 = *_q_value + ADD r3,r2,r1 //r3 = r2 + r1 + STREX r12,r3,[r0] //*_q_value = r3, r12 = error + TEQ r12,#0 //if error + BNE retry_fetchAndAddOrdered //then retry + MOV r0,r2 //return r2 + LDMIA sp!,{r12,pc} +} + +Q_CORE_EXPORT asm +bool QBasicAtomicPointer_testAndSetRelaxed(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicPointer_testAndSetRelease(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicPointer_testAndSetAcquire(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + CODE32 + //R0 = _q_value + //R1 = expectedValue + //R2 = newValue +retryPointer_testAndSetOrdered + LDREX r3,[r0] //r3 = *_q_value + EORS r3,r3,r1 //if (r3 == expectedValue) { + STREXEQ r3,r2,[r0] //*_q_value = newvalue, r3 = error + TEQEQ r3,#1 //if error + BEQ retryPointer_testAndSetOrdered //then goto retry } + RSBS r0,r3,#1 //return (r3 == 0) + MOVCC r0,#0 + BX r14 +} + +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndStoreRelaxed(void * volatile *_q_value, void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndStoreAcquire(void * volatile *_q_value, void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndStoreRelease(void * volatile *_q_value, void *newValue) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + CODE32 + //R0 = _q_value + //R1 = newValue +retryPointer_fetchAndStoreOrdered + LDREX r3,[r0] //r3 = *_q_value + STREX r2,r1,[r0] //*_q_value = newValue, r2 = error + TEQ r2,#0 //if error + BNE retryPointer_fetchAndStoreOrdered //then goto retry + MOV r0,r3 //return r3 + BX r14 +} + +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndAddRelaxed(void * volatile *_q_value, qptrdiff valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndAddRelease(void * volatile *_q_value, qptrdiff valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndAddAcquire(void * volatile *_q_value, qptrdiff valueToAdd) +{ + CODE32 + //fall through +} +Q_CORE_EXPORT asm +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + CODE32 + //R0 = _q_value + //R1 = valueToAdd + STMDB sp!,{r12,lr} +retryPointer_fetchAndAddOrdered + LDREX r2,[r0] //r2 = *_q_value + ADD r3,r2,r1 //r3 = r2 + r1 + STREX r12,r3,[r0] //*_q_value = r3, r12 = error + TEQ r12,#0 //if error + BNE retryPointer_fetchAndAddOrdered //then retry + MOV r0,r2 //return r2 + LDMIA sp!,{r12,pc} +} + +#pragma pop +#elif defined (Q_CC_GCCE) +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicInt_testAndSetRelaxed(volatile int *_q_value, int expectedValue, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicInt_testAndSetAcquire(volatile int *_q_value, int expectedValue, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicInt_testAndSetRelease(volatile int *_q_value, int expectedValue, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + //R0 = _q_value + //R1 = expectedValue + //R2 = newValue + asm("retry_testAndSetOrdered:"); + asm(" LDREX r3,[r0]"); //r3 = *_q_value + asm(" EORS r3,r3,r1"); //if (r3 == expectedValue) { + asm(" STREXEQ r3,r2,[r0]"); //*_q_value = newvalue, r3 = error + asm(" TEQEQ r3,#1"); //if error + asm(" BEQ retry_testAndSetOrdered"); //then goto retry } + asm(" RSBS r0,r3,#1"); //return (r3 == 0) + asm(" MOVCC r0,#0"); + asm(" BX r14"); +} + +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndStoreRelaxed(volatile int *_q_value, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndStoreAcquire(volatile int *_q_value, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndStoreRelease(volatile int *_q_value, int newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ +//R0 = _q_value +//R1 = newValue + asm("retry_fetchAndStoreOrdered:"); + asm(" LDREX r3,[r0]"); //r3 = *_q_value + asm(" STREX r2,r1,[r0]"); //*_q_value = newValue, r2 = error + asm(" TEQ r2,#0"); //if error + asm(" BNE retry_fetchAndStoreOrdered"); //then goto retry + asm(" MOV r0,r3"); //return r3 + asm(" BX r14"); +} + +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndAddRelaxed(volatile int *_q_value, int valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndAddAcquire(volatile int *_q_value, int valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndAddRelease(volatile int *_q_value, int valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + //R0 = _q_value + //R1 = valueToAdd + asm(" STMDB sp!,{r12,lr}"); + asm("retry_fetchAndAddOrdered:"); + asm(" LDREX r2,[r0]"); //r2 = *_q_value + asm(" ADD r3,r2,r1 "); //r3 = r2 + r1 + asm(" STREX r12,r3,[r0]"); //*_q_value = r3, r12 = error + asm(" TEQ r12,#0"); //if error + asm(" BNE retry_fetchAndAddOrdered"); //then retry + asm(" MOV r0,r2"); //return r2 + asm(" LDMIA sp!,{r12,pc}"); +} + +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicPointer_testAndSetRelaxed(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicPointer_testAndSetRelease(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicPointer_testAndSetAcquire(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + //R0 = _q_value + //R1 = expectedValue + //R2 = newValue + asm("retryPointer_testAndSetOrdered:"); + asm(" LDREX r3,[r0]"); //r3 = *_q_value + asm(" EORS r3,r3,r1"); //if (r3 == expectedValue) { + asm(" STREXEQ r3,r2,[r0]"); //*_q_value = newvalue, r3 = error + asm(" TEQEQ r3,#1"); //if error + asm(" BEQ retryPointer_testAndSetOrdered"); //then goto retry } + asm(" RSBS r0,r3,#1"); //return (r3 == 0) + asm(" MOVCC r0,#0"); + asm(" BX r14"); +} + +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndStoreRelaxed(void * volatile *_q_value, void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndStoreAcquire(void * volatile *_q_value, void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndStoreRelease(void * volatile *_q_value, void *newValue) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + //R0 = _q_value + //R1 = newValue + asm("retryPointer_fetchAndStoreOrdered:"); + asm(" LDREX r3,[r0]"); //r3 = *_q_value + asm(" STREX r2,r1,[r0]"); //*_q_value = newValue, r2 = error + asm(" TEQ r2,#0"); //if error + asm(" BNE retryPointer_fetchAndStoreOrdered"); //then goto retry + asm(" MOV r0,r3"); //return r3 + asm(" BX r14"); +} + +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndAddRelaxed(void * volatile *_q_value, qptrdiff valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndAddRelease(void * volatile *_q_value, qptrdiff valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndAddAcquire(void * volatile *_q_value, qptrdiff valueToAdd) +{ + //fall through +} +Q_CORE_EXPORT __declspec( naked ) +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + //R0 = _q_value + //R1 = valueToAdd + asm(" STMDB sp!,{r12,lr}"); + asm("retryPointer_fetchAndAddOrdered:"); + asm(" LDREX r2,[r0]"); //r2 = *_q_value + asm(" ADD r3,r2,r1"); //r3 = r2 + r1 + asm(" STREX r12,r3,[r0]"); //*_q_value = r3, r12 = error + asm(" TEQ r12,#0"); //if error + asm(" BNE retryPointer_fetchAndAddOrdered"); //then retry + asm(" MOV r0,r2"); //return r2 + asm(" LDMIA sp!,{r12,pc}"); +} +#else +#error unknown arm compiler +#endif +QT_END_NAMESPACE +#endif +#endif diff --git a/src/corelib/arch/symbian/qatomic_symbian.cpp b/src/corelib/arch/symbian/qatomic_symbian.cpp new file mode 100644 index 0000000000..9b997e1a70 --- /dev/null +++ b/src/corelib/arch/symbian/qatomic_symbian.cpp @@ -0,0 +1,527 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#ifdef SYMBIAN_E32_ATOMIC_API +#include +#endif + +#include + +QT_BEGIN_NAMESPACE + +// Heap and handle info printer. +// This way we can report on heap cells and handles that are really not owned by anything which still exists. +// This information can be used to detect whether memory leaks are happening, particularly if these numbers grow as the app is used more. +// This code is placed here as it happens to make it the very last static to be destroyed in a Qt app. The +// reason assumed is that this file appears before any other file declaring static data in the generated +// Symbian MMP file. This particular file was chosen as it is the earliest symbian specific file. +struct QSymbianPrintExitInfo +{ + QSymbianPrintExitInfo() + { + RThread().HandleCount(initProcessHandleCount, initThreadHandleCount); + initCells = User::CountAllocCells(); + } + ~QSymbianPrintExitInfo() + { + RProcess myProc; + TFullName fullName = myProc.FileName(); + TInt cells = User::CountAllocCells(); + TInt processHandleCount=0; + TInt threadHandleCount=0; + RThread().HandleCount(processHandleCount, threadHandleCount); + RDebug::Print(_L("%S exiting with %d allocated cells, %d handles"), + &fullName, + cells - initCells, + (processHandleCount + threadHandleCount) - (initProcessHandleCount + initThreadHandleCount)); + } + TInt initCells; + TInt initProcessHandleCount; + TInt initThreadHandleCount; +} symbian_printExitInfo; + +Q_CORE_EXPORT bool QBasicAtomicInt::isReferenceCountingNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicInt::isTestAndSetNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicInt::isFetchAndStoreNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicInt::isFetchAndAddNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicPointer_isTestAndSetNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicPointer_isFetchAndStoreNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +Q_CORE_EXPORT bool QBasicAtomicPointer_isFetchAndAddNative() +{ +#if !defined(SYMBIAN_E32_ATOMIC_API) && defined(QT_HAVE_ARMV6) + return true; +#else + return false; +#endif +} + +#ifdef SYMBIAN_E32_ATOMIC_API +//Symbian's API is SMP-safe when using SMP kernel, and cheap when using uniprocessor kernel + +//generate compiler error if casting assumptions are wrong (symbian64?) +__ASSERT_COMPILE(sizeof(int) == sizeof(TUint32)); +__ASSERT_COMPILE(sizeof(void *) == sizeof(TUint32)); + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + return static_cast(__e32_atomic_cas_ord32(_q_value, + reinterpret_cast(&expectedValue), newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetRelaxed(volatile int *_q_value, int expectedValue, int newValue) +{ + return static_cast(__e32_atomic_cas_rlx32(_q_value, + reinterpret_cast(&expectedValue), newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetAcquire(volatile int *_q_value, int expectedValue, int newValue) +{ + return static_cast(__e32_atomic_cas_acq32(_q_value, + reinterpret_cast(&expectedValue), newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetRelease(volatile int *_q_value, int expectedValue, int newValue) +{ + return static_cast(__e32_atomic_cas_rel32(_q_value, + reinterpret_cast(&expectedValue), newValue)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ + return static_cast(__e32_atomic_swp_ord32(_q_value, newValue)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreRelaxed(volatile int *_q_value, int newValue) +{ + return static_cast(__e32_atomic_swp_rlx32(_q_value, newValue)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreAcquire(volatile int *_q_value, int newValue) +{ + return static_cast(__e32_atomic_swp_acq32(_q_value, newValue)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreRelease(volatile int *_q_value, int newValue) +{ + return static_cast(__e32_atomic_swp_rel32(_q_value, newValue)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + return static_cast(__e32_atomic_add_ord32(_q_value, valueToAdd)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddRelaxed(volatile int *_q_value, int valueToAdd) +{ + return static_cast(__e32_atomic_add_rlx32(_q_value, valueToAdd)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddAcquire(volatile int *_q_value, int valueToAdd) +{ + return static_cast(__e32_atomic_add_acq32(_q_value, valueToAdd)); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddRelease(volatile int *_q_value, int valueToAdd) +{ + return static_cast(__e32_atomic_add_rel32(_q_value, valueToAdd)); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return static_cast(__e32_atomic_cas_ord_ptr(_q_value, + &expectedValue, + newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetRelaxed(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return static_cast(__e32_atomic_cas_rlx_ptr(_q_value, + &expectedValue, + newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetAcquire(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return static_cast(__e32_atomic_cas_acq_ptr(_q_value, + &expectedValue, + newValue)); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetRelease(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return static_cast(__e32_atomic_cas_rel_ptr(_q_value, + &expectedValue, + newValue)); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + return __e32_atomic_swp_ord_ptr(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreRelaxed(void * volatile *_q_value, void *newValue) +{ + return __e32_atomic_swp_rlx_ptr(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreAcquire(void * volatile *_q_value, void *newValue) +{ + return __e32_atomic_swp_acq_ptr(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreRelease(void * volatile *_q_value, void *newValue) +{ + return __e32_atomic_swp_rel_ptr(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return __e32_atomic_add_ord_ptr(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddRelaxed(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return __e32_atomic_add_rlx_ptr(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddAcquire(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return __e32_atomic_add_acq_ptr(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddRelease(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return __e32_atomic_add_rel_ptr(_q_value, valueToAdd); +} + +#else +//Symbian kernels 9.4 and earlier don't expose a suitable API + +//For ARMv6, the generic atomics are machine coded +#ifndef QT_HAVE_ARMV6 + +class QCriticalSection +{ +public: + QCriticalSection() { fastlock.CreateLocal(); } + ~QCriticalSection() { fastlock.Close(); } + void lock() { fastlock.Wait(); } + void unlock() { fastlock.Signal(); } + +private: + RFastLock fastlock; +}; + +QCriticalSection qAtomicCriticalSection; + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetOrdered(volatile int *_q_value, int expectedValue, int newValue) +{ + bool returnValue = false; + qAtomicCriticalSection.lock(); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreOrdered(volatile int *_q_value, int newValue) +{ + int returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = newValue; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddOrdered(volatile int *_q_value, int valueToAdd) +{ + int returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value += valueToAdd; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetOrdered(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + bool returnValue = false; + qAtomicCriticalSection.lock(); + if (*_q_value == expectedValue) { + *_q_value = newValue; + returnValue = true; + } + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreOrdered(void * volatile *_q_value, void *newValue) +{ + void *returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = newValue; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff valueToAdd) +{ + void *returnValue; + qAtomicCriticalSection.lock(); + returnValue = *_q_value; + *_q_value = reinterpret_cast(returnValue) + valueToAdd; + qAtomicCriticalSection.unlock(); + return returnValue; +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetRelaxed(volatile int *_q_value, int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetAcquire(volatile int *_q_value, int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +bool QBasicAtomicInt_testAndSetRelease(volatile int *_q_value, int expectedValue, int newValue) +{ + return QBasicAtomicInt_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreRelaxed(volatile int *_q_value, int newValue) +{ + return QBasicAtomicInt_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreAcquire(volatile int *_q_value, int newValue) +{ + return QBasicAtomicInt_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndStoreRelease(volatile int *_q_value, int newValue) +{ + return QBasicAtomicInt_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddRelaxed(volatile int *_q_value, int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddOrdered(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddAcquire(volatile int *_q_value, int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddOrdered(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +int QBasicAtomicInt_fetchAndAddRelease(volatile int *_q_value, int valueToAdd) +{ + return QBasicAtomicInt_fetchAndAddOrdered(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetRelaxed(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return QBasicAtomicPointer_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetAcquire(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return QBasicAtomicPointer_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +bool QBasicAtomicPointer_testAndSetRelease(void * volatile *_q_value, + void *expectedValue, + void *newValue) +{ + return QBasicAtomicPointer_testAndSetOrdered(_q_value, expectedValue, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreRelaxed(void * volatile *_q_value, void *newValue) +{ + return QBasicAtomicPointer_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreAcquire(void * volatile *_q_value, void *newValue) +{ + return QBasicAtomicPointer_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndStoreRelease(void * volatile *_q_value, void *newValue) +{ + return QBasicAtomicPointer_fetchAndStoreOrdered(_q_value, newValue); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddRelaxed(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return QBasicAtomicPointer_fetchAndAddOrdered(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddAcquire(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return QBasicAtomicPointer_fetchAndAddOrdered(_q_value, valueToAdd); +} + +Q_CORE_EXPORT +void *QBasicAtomicPointer_fetchAndAddRelease(void * volatile *_q_value, qptrdiff valueToAdd) +{ + return QBasicAtomicPointer_fetchAndAddOrdered(_q_value, valueToAdd); +} + +#endif // QT_HAVE_ARMV6 +#endif // SYMBIAN_E32_ATOMIC_API + +QT_END_NAMESPACE diff --git a/src/corelib/arch/symbian/qt_heapsetup_symbian.cpp b/src/corelib/arch/symbian/qt_heapsetup_symbian.cpp new file mode 100644 index 0000000000..27ed4bcd10 --- /dev/null +++ b/src/corelib/arch/symbian/qt_heapsetup_symbian.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt_hybridheap_symbian_p.h" + +#ifdef QT_USE_NEW_SYMBIAN_ALLOCATOR + +extern const TInt KHeapShrinkHysRatio = 0x800; + +/* + * \internal + * Called from the qtmain.lib application wrapper. + * Create a new heap as requested, but use the new allocator + */ +Q_CORE_EXPORT TInt qt_symbian_SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo) +{ + TInt r = KErrNone; + if (!aInfo.iAllocator && aInfo.iHeapInitialSize>0) + { + // new heap required + RHeap* pH = NULL; + r = UserHeap::CreateThreadHeap(aInfo, pH); + } + else if (aInfo.iAllocator) + { + // sharing a heap + RAllocator* pA = aInfo.iAllocator; + pA->Open(); + User::SwitchAllocator(pA); + } + return r; +} + +#ifndef NO_NAMED_LOCAL_CHUNKS +void TChunkCreateInfo::SetThreadHeap(TInt aInitialSize, TInt aMaxSize, const TDesC& aName) +{ + iType = TChunkCreate::ENormal | TChunkCreate::EData; + iMaxSize = aMaxSize; + iInitialBottom = 0; + iInitialTop = aInitialSize; + iAttributes |= TChunkCreate::ELocalNamed; + iName = &aName; + iOwnerType = EOwnerThread; +} +#endif // NO_NAMED_LOCAL_CHUNKS + +void Panic(TCdtPanic reason) +{ + _LIT(KCat, "QtHybridHeap"); + User::Panic(KCat, reason); +} + +#else /* QT_USE_NEW_SYMBIAN_ALLOCATOR */ + +#include + +/* + * \internal + * Called from the qtmain.lib application wrapper. + * Create a new heap as requested, using the default system allocator + */ +Q_CORE_EXPORT TInt qt_symbian_SetupThreadHeap(TBool aNotFirst, SStdEpocThreadCreateInfo& aInfo) +{ + return UserHeap::SetupThreadHeap(aNotFirst, aInfo); +} + +#endif /* QT_USE_NEW_SYMBIAN_ALLOCATOR */ diff --git a/src/corelib/arch/symbian/qt_hybridheap_symbian_p.h b/src/corelib/arch/symbian/qt_hybridheap_symbian_p.h new file mode 100644 index 0000000000..d1ce7056f4 --- /dev/null +++ b/src/corelib/arch/symbian/qt_hybridheap_symbian_p.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_HYBRIDHEAP_SYMBIAN_H +#define QT_HYBRIDHEAP_SYMBIAN_H + +#include +#include + +#if !defined(__SYMBIAN_KERNEL_HYBRID_HEAP__) && !defined(__WINS__) +//Enable the (backported) new allocator. When it is available in OS, +//this flag should be disabled for that OS version onward +#define QT_USE_NEW_SYMBIAN_ALLOCATOR +#endif + +#ifdef QT_USE_NEW_SYMBIAN_ALLOCATOR + +#ifdef Q_CC_RVCT +#pragma push +#pragma arm +#pragma Otime +#pragma O2 +#endif + +#include "common_p.h" +#ifdef QT_SYMBIAN_HAVE_U32STD_H +#include +#endif +#ifdef QT_SYMBIAN_HAVE_E32BTRACE_H +#include +// enables btrace code compiling into +#define ENABLE_BTRACE +#endif +#ifdef __KERNEL_MODE__ +#include +#endif +#include "dla_p.h" +#ifndef __KERNEL_MODE__ +#include "slab_p.h" +#include "page_alloc_p.h" +#endif +#include "heap_hybrid_p.h" + +// disabling Symbian import/export macros to prevent heap_hybrid.cpp, copied from Symbian^4, from exporting symbols in arm builds +// this minimises the code changes to heap_hybrid.cpp to ease future integration +#undef UEXPORT_C +#define UEXPORT_C +#undef EXPORT_C +#define EXPORT_C +#undef IMPORT_D +#define IMPORT_D + +// disabling code ported from Symbian^4 that we don't want/can't have in earlier platforms +#define QT_SYMBIAN4_ALLOCATOR_UNWANTED_CODE + +#if defined(SYMBIAN_VERSION_9_1) || defined(SYMBIAN_VERSION_9_2) || defined(SYMBIAN_VERSION_9_3) || defined(SYMBIAN_VERSION_9_4) || defined(SYMBIAN_VERSION_SYMBIAN2) +#define NO_NAMED_LOCAL_CHUNKS +#endif + +// disabling the BTrace components of heap checking macros +#ifndef ENABLE_BTRACE +inline int noBTrace() {return 0;} +#define BTraceContext12(a,b,c,d,e) noBTrace() +#endif + +// declare ETHeapBadDebugFailParameter, where missing +#define ETHeapBadDebugFailParameter ((TCdtPanic)213) + +#ifndef QT_SYMBIAN_HAVE_U32STD_H +struct SThreadCreateInfo + { + TAny* iHandle; + TInt iType; + TThreadFunction iFunction; + TAny* iPtr; + TAny* iSupervisorStack; + TInt iSupervisorStackSize; + TAny* iUserStack; + TInt iUserStackSize; + TInt iInitialThreadPriority; + TPtrC iName; + TInt iTotalSize; // Size including any extras (must be a multiple of 8 bytes) + }; + +struct SStdEpocThreadCreateInfo : public SThreadCreateInfo + { + RAllocator* iAllocator; + TInt iHeapInitialSize; + TInt iHeapMaxSize; + TInt iPadding; // Make structure size a multiple of 8 bytes + }; + +class TChunkCreate + { +public: + // Attributes for chunk creation that are used by both euser and the kernel + // by classes TChunkCreateInfo and SChunkCreateInfo, respectively. + enum TChunkCreateAtt + { + ENormal = 0x00000000, + EDoubleEnded = 0x00000001, + EDisconnected = 0x00000002, + ECache = 0x00000003, + EMappingMask = 0x0000000f, + ELocal = 0x00000000, + EGlobal = 0x00000010, + EData = 0x00000000, + ECode = 0x00000020, + EMemoryNotOwned = 0x00000040, + + // Force local chunk to be named. Only required for thread heap + // chunks, all other local chunks should be nameless. + ELocalNamed = 0x000000080, + + // Make global chunk read only to all processes but the controlling owner + EReadOnly = 0x000000100, + + // Paging attributes for chunks. + EPagingUnspec = 0x00000000, + EPaged = 0x80000000, + EUnpaged = 0x40000000, + EPagingMask = EPaged | EUnpaged, + + EChunkCreateAttMask = EMappingMask | EGlobal | ECode | + ELocalNamed | EReadOnly | EPagingMask, + }; +public: + TUint iAtt; + TBool iForceFixed; + TInt iInitialBottom; + TInt iInitialTop; + TInt iMaxSize; + TUint8 iClearByte; + }; + +#endif // QT_SYMBIAN_HAVE_U32STD_H + +#endif /* QT_USE_NEW_SYMBIAN_ALLOCATOR */ + +#endif /* QT_HYBRIDHEAP_SYMBIAN_H */ diff --git a/src/corelib/arch/symbian/slab_p.h b/src/corelib/arch/symbian/slab_p.h new file mode 100644 index 0000000000..2451bbf151 --- /dev/null +++ b/src/corelib/arch/symbian/slab_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __KERNEL_MODE__ + +class slab; +class slabhdr; +#define MAXSLABSIZE 56 +#define PAGESHIFT 12 +#define PAGESIZE (1<>3) : ((unsigned) bits>>1)) + +#define LOWBIT(bits) (((unsigned) bits&3) ? 1 - ((unsigned)bits&1) : 3 - (((unsigned)bits>>2)&1)) + +#define ZEROBITS(header) (((unsigned)header & 0x70000000) ? 0 : 1) + +class slabhdr +{ + public: + unsigned iHeader; + // made up of + // bits | 31 | 30..28 | 27..18 | 17..12 | 11..8 | 7..0 | + // +----------+--------+--------+--------+---------+----------+ + // field | floating | zero | used-4 | size | pagemap | free pos | + // + slab** iParent; // reference to iParent's pointer to this slab in tree + slab* iChild1; // 1st iChild in tree + slab* iChild2; // 2nd iChild in tree +}; + +const TInt KMaxSlabPayload = SLABSIZE - sizeof(slabhdr); +#define MAXUSEDM4BITS 0x0fc00000 +#define FLOATING_BIT 0x80000000 + +inline unsigned HeaderFloating(unsigned h) +{return (h&0x80000000);} +const unsigned maxuse = (SLABSIZE - sizeof(slabhdr))>>2; +const unsigned firstpos = sizeof(slabhdr)>>2; + +#ifdef _DEBUG +#define CHECKTREE(x) DoCheckSlabTree(x,EFalse) +#define CHECKSLAB(s,t,p) DoCheckSlab(s,t,p) +#define CHECKSLABBFR(s,p) {TUint32 b[4]; BuildPartialSlabBitmap(b,s,p);} +#else +#define CHECKTREE(x) (void)0 +#define CHECKSLAB(s,t,p) (void)0 +#define CHECKSLABBFR(s,p) (void)0 +#endif + +class slabset +{ + public: + slab* iPartial; +}; + +class slab : public slabhdr +{ + public: + void Init(unsigned clz); + //static slab* SlabFor( void* p); + static slab* SlabFor(const void* p) ; + unsigned char iPayload[SLABSIZE-sizeof(slabhdr)]; +}; + +class page +{ + public: + inline static page* PageFor(slab* s); + //slab iSlabs; + slab iSlabs[slabsperpage]; +}; + + +inline page* page::PageFor(slab* s) +{ + return reinterpret_cast((unsigned(s))&~(PAGESIZE-1)); +} + + +#endif // __KERNEL_MODE__ diff --git a/src/corelib/arch/vxworks/arch.pri b/src/corelib/arch/vxworks/arch.pri new file mode 100644 index 0000000000..a7686186b0 --- /dev/null +++ b/src/corelib/arch/vxworks/arch.pri @@ -0,0 +1,6 @@ +# +# VxWorks generic +# +*-ppc-* { + SOURCES += qatomic_ppc.s +} diff --git a/src/corelib/arch/vxworks/qatomic_ppc.s b/src/corelib/arch/vxworks/qatomic_ppc.s new file mode 100644 index 0000000000..03971e89e8 --- /dev/null +++ b/src/corelib/arch/vxworks/qatomic_ppc.s @@ -0,0 +1,415 @@ + + .align 2 + .globl q_atomic_test_and_set_int + .globl .q_atomic_test_and_set_int +q_atomic_test_and_set_int: +.q_atomic_test_and_set_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_int-.q_atomic_test_and_set_int + .short 25 + .byte "q_atomic_test_and_set_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_int + .globl .q_atomic_test_and_set_acquire_int +q_atomic_test_and_set_acquire_int: +.q_atomic_test_and_set_acquire_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+16 + stwcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_int-.q_atomic_test_and_set_acquire_int + .short 33 + .byte "q_atomic_test_and_set_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_int + .globl .q_atomic_test_and_set_release_int +q_atomic_test_and_set_release_int: +.q_atomic_test_and_set_release_int: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_release_int: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_int-.q_atomic_test_and_set_release_int + .short 33 + .byte "q_atomic_test_and_set_release_int" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_ptr + .globl .q_atomic_test_and_set_ptr +q_atomic_test_and_set_ptr: +.q_atomic_test_and_set_ptr: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_ptr-.q_atomic_test_and_set_ptr + .short 25 + .byte "q_atomic_test_and_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_acquire_ptr + .globl .q_atomic_test_and_set_acquire_ptr +q_atomic_test_and_set_acquire_ptr: +.q_atomic_test_and_set_acquire_ptr: + lwarx 6,0,3 + xor. 6,6,4 + bne $+16 + stwcx. 5,0,3 + bne- $-16 + isync + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_acquire_ptr-.q_atomic_test_and_set_acquire_ptr + .short 25 + .byte "q_atomic_test_and_set_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_test_and_set_release_ptr + .globl .q_atomic_test_and_set_release_ptr +q_atomic_test_and_set_release_ptr: +.q_atomic_test_and_set_release_ptr: + lwarx 6,0,3 + xor. 6,6,4 + bne $+12 + stwcx. 5,0,3 + bne- $-16 + subfic 3,6,0 + adde 3,3,6 + blr +LT..q_atomic_test_and_set_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,3,0 + .long 0 + .long LT..q_atomic_test_and_set_release_ptr-.q_atomic_test_and_set_release_ptr + .short 33 + .byte "q_atomic_test_and_set_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_increment + .globl .q_atomic_increment +q_atomic_increment: +.q_atomic_increment: + lwarx 4,0,3 + addi 4,4,1 + stwcx. 4,0,3 + bne- $-12 + mr 3,4 + blr +LT..q_atomic_increment: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_increment-.q_atomic_increment + .short 18 + .byte "q_atomic_increment" + .align 2 + + .align 2 + .globl q_atomic_decrement + .globl .q_atomic_decrement +q_atomic_decrement: +.q_atomic_decrement: + lwarx 4,0,3 + subi 4,4,1 + stwcx. 4,0,3 + bne- $-12 + mr 3,4 + blr +LT..q_atomic_decrement: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_decrement-.q_atomic_decrement + .short 18 + .byte "q_atomic_decrement" + .align 2 + + .align 2 + .globl q_atomic_set_int + .globl .q_atomic_set_int +q_atomic_set_int: +.q_atomic_set_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_set_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_int-.q_atomic_set_int + .short 16 + .byte "q_atomic_set_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_int + .globl .q_atomic_fetch_and_store_acquire_int +q_atomic_fetch_and_store_acquire_int: +.q_atomic_fetch_and_store_acquire_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_int-.q_atomic_fetch_and_store_acquire_int + .short 16 + .byte "q_atomic_fetch_and_store_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_int + .globl .q_atomic_fetch_and_store_release_int +q_atomic_fetch_and_store_release_int: +.q_atomic_fetch_and_store_release_int: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_fetch_and_store_release_int: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_int-.q_atomic_fetch_and_store_release_int + .short 16 + .byte "q_atomic_fetch_and_store_release_int" + .align 2 + + .align 2 + .globl q_atomic_set_ptr + .globl .q_atomic_set_ptr +q_atomic_set_ptr: +.q_atomic_set_ptr: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_set_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_set_ptr-.q_atomic_set_ptr + .short 16 + .byte "q_atomic_set_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_acquire_ptr + .globl .q_atomic_fetch_and_store_acquire_ptr +q_atomic_fetch_and_store_acquire_ptr: +.q_atomic_fetch_and_store_acquire_ptr: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_store_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_acquire_ptr-.q_atomic_fetch_and_store_acquire_ptr + .short 16 + .byte "q_atomic_fetch_and_store_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_store_release_ptr + .globl .q_atomic_fetch_and_store_release_ptr +q_atomic_fetch_and_store_release_ptr: +.q_atomic_fetch_and_store_release_ptr: + lwarx 5,0,3 + stwcx. 4,0,3 + bne- $-8 + mr 3,5 + blr +LT..q_atomic_fetch_and_store_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,2,0 + .long 0 + .long LT..q_atomic_fetch_and_store_release_ptr-.q_atomic_fetch_and_store_release_ptr + .short 16 + .byte "q_atomic_fetch_and_store_release_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_int + .globl .q_atomic_fetch_and_add_int +q_atomic_fetch_and_add_int: +.q_atomic_fetch_and_add_int: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_int-.q_atomic_fetch_and_add_int + .short 18 + .byte "q_atomic_fetch_and_add_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_int + .globl .q_atomic_fetch_and_add_acquire_int +q_atomic_fetch_and_add_acquire_int: +.q_atomic_fetch_and_add_acquire_int: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_int-.q_atomic_fetch_and_add_acquire_int + .short 18 + .byte "q_atomic_fetch_and_add_acquire_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_int + .globl .q_atomic_fetch_and_add_release_int +q_atomic_fetch_and_add_release_int: +.q_atomic_fetch_and_add_release_int: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_release_int: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_int-.q_atomic_fetch_and_add_release_int + .short 34 + .byte "q_atomic_fetch_and_add_release_int" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_ptr + .globl .q_atomic_fetch_and_add_ptr +q_atomic_fetch_and_add_ptr: +.q_atomic_fetch_and_add_ptr: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_ptr-.q_atomic_fetch_and_add_ptr + .short 26 + .byte "q_atomic_fetch_and_add_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_acquire_ptr + .globl .q_atomic_fetch_and_add_acquire_ptr +q_atomic_fetch_and_add_acquire_ptr: +.q_atomic_fetch_and_add_acquire_ptr: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + isync + mr 3,5 + blr +LT..q_atomic_fetch_and_add_acquire_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_acquire_ptr-.q_atomic_fetch_and_add_acquire_ptr + .short 34 + .byte "q_atomic_fetch_and_add_acquire_ptr" + .align 2 + + .align 2 + .globl q_atomic_fetch_and_add_release_ptr + .globl .q_atomic_fetch_and_add_release_ptr +q_atomic_fetch_and_add_release_ptr: +.q_atomic_fetch_and_add_release_ptr: + lwarx 5,0,3 + add 6,4,5 + stwcx. 6,0,3 + bne- $-12 + mr 3,5 + blr +LT..q_atomic_fetch_and_add_release_ptr: + .long 0 + .byte 0,9,32,64,0,0,1,0 + .long 0 + .long LT..q_atomic_fetch_and_add_release_ptr-.q_atomic_fetch_and_add_release_ptr + .short 34 + .byte "q_atomic_fetch_and_add_release_ptr" + .align 2 + +_section_.text: + .long _section_.text diff --git a/src/corelib/arch/windows/arch.pri b/src/corelib/arch/windows/arch.pri new file mode 100644 index 0000000000..d42374b98f --- /dev/null +++ b/src/corelib/arch/windows/arch.pri @@ -0,0 +1,3 @@ +# +# Windows architecture +# diff --git a/src/corelib/arch/x86_64/arch.pri b/src/corelib/arch/x86_64/arch.pri new file mode 100644 index 0000000000..4145b7b133 --- /dev/null +++ b/src/corelib/arch/x86_64/arch.pri @@ -0,0 +1,4 @@ +# +# AMD64 architecture +# +solaris-cc*:SOURCES += $$QT_ARCH_CPP/qatomic_sun.s diff --git a/src/corelib/arch/x86_64/qatomic_sun.s b/src/corelib/arch/x86_64/qatomic_sun.s new file mode 100644 index 0000000000..37969e61cb --- /dev/null +++ b/src/corelib/arch/x86_64/qatomic_sun.s @@ -0,0 +1,91 @@ + .code64 + + .globl q_atomic_increment + .type q_atomic_increment,@function + .section .text, "ax" + .align 16 +q_atomic_increment: + lock + incl (%rdi) + setne %al + ret + .size q_atomic_increment,.-q_atomic_increment + + .globl q_atomic_decrement + .type q_atomic_decrement,@function + .section .text, "ax" + .align 16 +q_atomic_decrement: + lock + decl (%rdi) + setne %al + ret + .size q_atomic_decrement,.-q_atomic_decrement + + .globl q_atomic_test_and_set_int + .type q_atomic_test_and_set_int, @function + .section .text, "ax" + .align 16 +q_atomic_test_and_set_int: + movl %esi,%eax + lock + cmpxchgl %edx,(%rdi) + movl $0,%eax + sete %al + ret + .size q_atomic_test_and_set_int, . - q_atomic_test_and_set_int + + .globl q_atomic_set_int + .type q_atomic_set_int,@function + .section .text, "ax" + .align 16 +q_atomic_set_int: + xchgl %esi,(%rdi) + movl %esi,%eax + ret + .size q_atomic_set_int,.-q_atomic_set_int + + .globl q_atomic_fetch_and_add_int + .type q_atomic_fetch_and_add_int,@function + .section .text, "ax" + .align 16 +q_atomic_fetch_and_add_int: + lock + xaddl %esi,(%rdi) + movl %esi, %eax + ret + .size q_atomic_fetch_and_add_int,.-q_atomic_fetch_and_add_int + + .globl q_atomic_test_and_set_ptr + .type q_atomic_test_and_set_ptr, @function + .section .text, "ax" + .align 16 +q_atomic_test_and_set_ptr: + movq %rsi,%rax + lock + cmpxchgq %rdx,(%rdi) + movq $0, %rax + sete %al + ret + .size q_atomic_test_and_set_ptr, . - q_atomic_test_and_set_ptr + + .globl q_atomic_set_ptr + .type q_atomic_set_ptr,@function + .section .text, "ax" + .align 16 +q_atomic_set_ptr: + xchgq %rsi,(%rdi) + movq %rsi,%rax + ret + .size q_atomic_set_ptr,.-q_atomic_set_ptr + + .globl q_atomic_fetch_and_add_ptr + .type q_atomic_fetch_and_add_ptr,@function + .section .text, "ax" + .align 16 +q_atomic_fetch_and_add_ptr: + lock + xaddq %rsi,(%rdi) + movq %rsi,%rax + ret + .size q_atomic_fetch_and_add_ptr,.-q_atomic_fetch_and_add_ptr diff --git a/src/corelib/codecs/codecs.pri b/src/corelib/codecs/codecs.pri new file mode 100644 index 0000000000..46d7dd46da --- /dev/null +++ b/src/corelib/codecs/codecs.pri @@ -0,0 +1,59 @@ +# Qt core library codecs module + +HEADERS += \ + codecs/qisciicodec_p.h \ + codecs/qlatincodec_p.h \ + codecs/qsimplecodec_p.h \ + codecs/qtextcodec_p.h \ + codecs/qtextcodec.h \ + codecs/qtsciicodec_p.h \ + codecs/qutfcodec_p.h \ + codecs/qtextcodecplugin.h + +SOURCES += \ + codecs/qisciicodec.cpp \ + codecs/qlatincodec.cpp \ + codecs/qsimplecodec.cpp \ + codecs/qtextcodec.cpp \ + codecs/qtsciicodec.cpp \ + codecs/qutfcodec.cpp \ + codecs/qtextcodecplugin.cpp + +unix { + SOURCES += codecs/qfontlaocodec.cpp + + contains(QT_CONFIG,iconv) { + HEADERS += codecs/qiconvcodec_p.h + SOURCES += codecs/qiconvcodec.cpp + } else:contains(QT_CONFIG,gnu-libiconv) { + HEADERS += codecs/qiconvcodec_p.h + SOURCES += codecs/qiconvcodec.cpp + + DEFINES += GNU_LIBICONV + !mac:LIBS_PRIVATE *= -liconv + } else:contains(QT_CONFIG,sun-libiconv) { + HEADERS += codecs/qiconvcodec_p.h + SOURCES += codecs/qiconvcodec.cpp + DEFINES += GNU_LIBICONV + } else:!symbian { + # no iconv, so we put all plugins in the library + HEADERS += \ + ../plugins/codecs/cn/qgb18030codec.h \ + ../plugins/codecs/jp/qeucjpcodec.h \ + ../plugins/codecs/jp/qjiscodec.h \ + ../plugins/codecs/jp/qsjiscodec.h \ + ../plugins/codecs/kr/qeuckrcodec.h \ + ../plugins/codecs/tw/qbig5codec.h \ + ../plugins/codecs/jp/qfontjpcodec.h + SOURCES += \ + ../plugins/codecs/cn/qgb18030codec.cpp \ + ../plugins/codecs/jp/qjpunicode.cpp \ + ../plugins/codecs/jp/qeucjpcodec.cpp \ + ../plugins/codecs/jp/qjiscodec.cpp \ + ../plugins/codecs/jp/qsjiscodec.cpp \ + ../plugins/codecs/kr/qeuckrcodec.cpp \ + ../plugins/codecs/tw/qbig5codec.cpp \ + ../plugins/codecs/jp/qfontjpcodec.cpp + } +} +symbian:LIBS += -lcharconv diff --git a/src/corelib/codecs/codecs.qdoc b/src/corelib/codecs/codecs.qdoc new file mode 100644 index 0000000000..c88f073f28 --- /dev/null +++ b/src/corelib/codecs/codecs.qdoc @@ -0,0 +1,532 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \group codecs + \title Codecs + \ingroup groups + \brief Codec support in Qt. + + These codecs provide facilities for conversion between Unicode and + specific text encodings. + + \generatelist{related} +*/ + +/*! + \page codec-big5.html + \title Big5 Text Codec + \ingroup codecs + + The Big5 codec provides conversion to and from the Big5 encoding. + The code was originally contributed by Ming-Che Chuang + \ for the Big-5+ encoding, and was + included in Qt with the author's permission, and the grateful + thanks of the Qt team. (Note: Ming-Che's code is QPL'd, as + per an mail to qt-info@nokia.com.) + + However, since Big-5+ was never formally approved, and was never + used by anyone, the Taiwan Free Software community and the Li18nux + Big5 Standard Subgroup agree that the de-facto standard Big5-ETen + (zh_TW.Big5 or zh_TW.TW-Big5) be used instead. + + The Big5 is currently implemented as a pure subset of the + Big5-HKSCS codec, so more fine-tuning is needed to make it + identical to the standard Big5 mapping as determined by + Li18nux-Big5. See \l{http://www.autrijus.org/xml/} for the draft + Big5 (2002) standard. + + James Su \ \ + generated the Big5-HKSCS-to-Unicode tables with a very + space-efficient algorithm. He generously donated his code to glibc + in May 2002. Subsequently, James has kindly allowed Anthony Fok + \ \ to adapt the code + for Qt. + + \legalese + Copyright (C) 2000 Ming-Che Chuang \BR + Copyright (C) 2002 James Su, Turbolinux Inc. \BR + Copyright (C) 2002 Anthony Fok, ThizLinux Laboratory Ltd. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-big5hkscs.html + \title Big5-HKSCS Text Codec + \ingroup codecs + + The Big5-HKSCS codec provides conversion to and from the + Big5-HKSCS encoding. + + The codec grew out of the QBig5Codec originally contributed by + Ming-Che Chuang \. James Su + \ \ and Anthony Fok + \ \ implemented HKSCS-1999 + QBig5hkscsCodec for Qt-2.3.x, but it was too late in Qt development + schedule to be officially included in the Qt-2.3.x series. + + Wu Yi \ ported the HKSCS-1999 QBig5hkscsCodec to + Qt-3.0.1 in March 2002. + + With the advent of the new HKSCS-2001 standard, James Su + \ \ generated the + Big5-HKSCS<->Unicode tables with a very space-efficient algorithm. + He generously donated his code to glibc in May 2002. Subsequently, + James has generously allowed Anthony Fok to adapt the code for + Qt-3.0.5. + + Currently, the Big5-HKSCS tables are generated from the following + sources, and with the Euro character added: + \list 1 + \o \l{http://www.microsoft.com/typography/unicode/950.txt} + \o \l{http://www.info.gov.hk/digital21/chi/hkscs/download/big5-iso.txt} + \o \l{http://www.info.gov.hk/digital21/chi/hkscs/download/big5cmp.txt} + \endlist + + There may be more fine-tuning to the QBig5hkscsCodec to maximize its + compatibility with the standard Big5 (2002) mapping as determined by + Li18nux Big5 Standard Subgroup. See \l{http://www.autrijus.org/xml/} + for the various Big5 CharMapML tables. + + \legalese + Copyright (C) 2000 Ming-Che Chuang \BR + Copyright (C) 2001, 2002 James Su, Turbolinux Inc. \BR + Copyright (C) 2002 WU Yi, HancomLinux Inc. \BR + Copyright (C) 2001, 2002 Anthony Fok, ThizLinux Laboratory Ltd. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-eucjp.html + \title EUC-JP Text Codec + \ingroup codecs + + The EUC-JP codec provides conversion to and from EUC-JP, the main + legacy encoding for Unix machines in Japan. + + The environment variable \c UNICODEMAP_JP can be used to + fine-tune the JIS, Shift-JIS, and EUC-JP codecs. The \l{ISO + 2022-JP (JIS) Text Codec} documentation describes how to use this + variable. + + Most of the code here was written by Serika Kurusugawa, + a.k.a. Junji Takagi, and is included in Qt with the author's + permission and the grateful thanks of the Qt team. Here is + the copyright statement for that code: + + \legalese + + Copyright (C) 1999 Serika Kurusugawa. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS". + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-euckr.html + \title EUC-KR Text Codec + \ingroup codecs + + The EUC-KR codec provides conversion to and from EUC-KR, KR, the + main legacy encoding for Unix machines in Korea. + + It was largely written by Mizi Research Inc. Here is the + copyright statement for the code as it was at the point of + contribution. The subsequent modifications are covered by + the usual copyright for Qt. + + \legalese + + Copyright (C) 1999-2000 Mizi Research Inc. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-gbk.html + \title GBK Text Codec + \ingroup codecs + + The GBK codec provides conversion to and from the Chinese + GB18030/GBK/GB2312 encoding. + + GBK, formally the Chinese Internal Code Specification, is a commonly + used extension of GB 2312-80. Microsoft Windows uses it under the + name codepage 936. + + GBK has been superseded by the new Chinese national standard + GB 18030-2000, which added a 4-byte encoding while remaining + compatible with GB2312 and GBK. The new GB 18030-2000 may be described + as a special encoding of Unicode 3.x and ISO-10646-1. + + Special thanks to charset gurus Markus Scherer (IBM), + Dirk Meyer (Adobe Systems) and Ken Lunde (Adobe Systems) for publishing + an excellent GB 18030-2000 summary and specification on the Internet. + Some must-read documents are: + + \list + \o \l{ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/pdf/GB18030_Summary.pdf} + \o \l{http://oss.software.ibm.com/cvs/icu/~checkout~/charset/source/gb18030/gb18030.html} + \o \l{http://oss.software.ibm.com/cvs/icu/~checkout~/charset/data/xml/gb-18030-2000.xml} + \endlist + + The GBK codec was contributed to Qt by + Justin Yu \ and + Sean Chen \. They may also be reached at + Yu Mingjian \, \ + Chen Xiangyang \ + + The GB18030 codec Qt functions were contributed to Qt by + James Su \, \ + who pioneered much of GB18030 development on GNU/Linux systems. + + The GB18030 codec was contributed to Qt by + Anthony Fok \, \ + using a Perl script to generate C++ tables from gb-18030-2000.xml + while merging contributions from James Su, Justin Yu and Sean Chen. + A copy of the source Perl script is available at + \l{http://people.debian.org/~foka/gb18030/gen-qgb18030codec.pl} + + The copyright notice for their code follows: + + \legalese + Copyright (C) 2000 TurboLinux, Inc. Written by Justin Yu and Sean Chen. \BR + Copyright (C) 2001, 2002 Turbolinux, Inc. Written by James Su. \BR + Copyright (C) 2001, 2002 ThizLinux Laboratory Ltd. Written by Anthony Fok. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codecs-jis.html + \title ISO 2022-JP (JIS) Text Codec + \ingroup codecs + + The JIS codec provides conversion to and from ISO 2022-JP. + + The environment variable \c UNICODEMAP_JP can be used to + fine-tune the JIS, Shift-JIS, and EUC-JP codecs. The mapping + names are as for the Japanese XML working group's \link + http://www.y-adagio.com/public/standards/tr_xml_jpf/toc.htm XML + Japanese Profile\endlink, because it names and explains all the + widely used mappings. Here are brief descriptions, written by + Serika Kurusugawa: + + \list + + \o "unicode-0.9" or "unicode-0201" for Unicode style. This assumes + JISX0201 for 0x00-0x7f. (0.9 is a table version of jisx02xx mapping + used for Unicode 1.1.) + + \o "unicode-ascii" This assumes US-ASCII for 0x00-0x7f; some + chars (JISX0208 0x2140 and JISX0212 0x2237) are different from + Unicode 1.1 to avoid conflict. + + \o "open-19970715-0201" ("open-0201" for convenience) or + "jisx0221-1995" for JISX0221-JISX0201 style. JIS X 0221 is JIS + version of Unicode, but a few chars (0x5c, 0x7e, 0x2140, 0x216f, + 0x2131) are different from Unicode 1.1. This is used when 0x5c is + treated as YEN SIGN. + + \o "open-19970715-ascii" ("open-ascii" for convenience) for + JISX0221-ASCII style. This is used when 0x5c is treated as REVERSE + SOLIDUS. + + \o "open-19970715-ms" ("open-ms" for convenience) or "cp932" for + Microsoft Windows style. Windows Code Page 932. Some chars (0x2140, + 0x2141, 0x2142, 0x215d, 0x2171, 0x2172) are different from Unicode + 1.1. + + \o "jdk1.1.7" for Sun's JDK style. Same as Unicode 1.1, except that + JIS 0x2140 is mapped to UFF3C. Either ASCII or JISX0201 can be used + for 0x00-0x7f. + + \endlist + + In addition, the extensions "nec-vdc", "ibm-vdc" and "udc" are + supported. + + For example, if you want to use Unicode style conversion but with + NEC's extension, set \c UNICODEMAP_JP to \c {unicode-0.9, + nec-vdc}. (You will probably need to quote that in a shell + command.) + + Most of the code here was written by Serika Kurusugawa, + a.k.a. Junji Takagi, and is included in Qt with the author's + permission and the grateful thanks of the Qt team. Here is + the copyright statement for that code: + + \legalese + + Copyright (C) 1999 Serika Kurusugawa. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS". + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-sjis.html + \title Shift-JIS Text Codec + \ingroup codecs + + The Shift-JIS codec provides conversion to and from Shift-JIS, an + encoding of JIS X 0201 Latin, JIS X 0201 Kana and JIS X 0208. + + The environment variable \c UNICODEMAP_JP can be used to + fine-tune the codec. The \l{ISO 2022-JP (JIS) Text Codec} + documentation describes how to use this variable. + + Most of the code here was written by Serika Kurusugawa, a.k.a. + Junji Takagi, and is included in Qt with the author's permission + and the grateful thanks of the Qt team. Here is the + copyright statement for the code as it was at the point of + contribution. The subsequent modifications are covered by + the usual copyright for Qt. + + \legalese + + Copyright (C) 1999 Serika Kurusugawa. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS". + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ + +/*! + \page codec-tscii.html + \title TSCII Text Codec + \ingroup codecs + + The TSCII codec provides conversion to and from the Tamil TSCII + encoding. + + TSCII, formally the Tamil Standard Code Information Interchange + specification, is a commonly used charset for Tamils. The + official page for the standard is at + \link http://www.tamil.net/tscii/ http://www.tamil.net/tscii/\endlink + + This codec uses the mapping table found at + \link http://www.geocities.com/Athens/5180/tsciiset.html + http://www.geocities.com/Athens/5180/tsciiset.html\endlink. + Tamil uses composed Unicode which might cause some + problems if you are using Unicode fonts instead of TSCII fonts. + + Most of the code was written by Hans Petter Bieker and is + included in Qt with the author's permission and the grateful + thanks of the Qt team. Here is the copyright statement for + the code as it was at the point of contribution. The + subsequent modifications are covered by the usual copyright for + Qt: + + \legalese + + Copyright (c) 2000 Hans Petter Bieker. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + \list 1 + \o Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + \o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + \endlist + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + \endlegalese +*/ diff --git a/src/corelib/codecs/qfontlaocodec.cpp b/src/corelib/codecs/qfontlaocodec.cpp new file mode 100644 index 0000000000..981492c54a --- /dev/null +++ b/src/corelib/codecs/qfontlaocodec.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfontlaocodec_p.h" +#include "qlist.h" + +#ifndef QT_NO_CODECS +#ifndef QT_NO_BIG_CODECS + +QT_BEGIN_NAMESPACE + +static unsigned char const unicode_to_mulelao[256] = + { + // U+0E80 + 0x00, 0xa1, 0xa2, 0x00, 0xa4, 0x00, 0x00, 0xa7, + 0xa8, 0x00, 0xaa, 0x00, 0x00, 0xad, 0x00, 0x00, + // U+0E90 + 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0xb7, + 0x00, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + // U+0EA0 + 0x00, 0xc1, 0xc2, 0xc3, 0x00, 0xc5, 0x00, 0xc7, + 0x00, 0x00, 0xca, 0xcb, 0x00, 0xcd, 0xce, 0xcf, + // U+0EB0 + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0x00, 0xdb, 0xdc, 0xdd, 0x00, 0x00, + // U+0EC0 + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0x00, 0xe6, 0x00, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0x00, 0x00, + // U+0ED0 + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0x00, 0x00, 0xfc, 0xfd, 0x00, 0x00, + // U+0EE0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // U+0EF0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + +QFontLaoCodec::~QFontLaoCodec() +{ +} + +QByteArray QFontLaoCodec::name() const +{ + return "mulelao-1"; +} + +int QFontLaoCodec::mibEnum() const +{ + return -4242; +} + +QString QFontLaoCodec::convertToUnicode(const char *, int, ConverterState *) const +{ + return QString(); +} + +QByteArray QFontLaoCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *) const +{ + QByteArray rstring(len, Qt::Uninitialized); + uchar *rdata = (uchar *) rstring.data(); + const QChar *sdata = uc; + int i = 0; + for (; i < len; ++i, ++sdata, ++rdata) { + if (sdata->unicode() < 0x80) { + *rdata = (uchar) sdata->unicode(); + } else if (sdata->unicode() >= 0x0e80 && sdata->unicode() <= 0x0eff) { + uchar lao = unicode_to_mulelao[sdata->unicode() - 0x0e80]; + if (lao) + *rdata = lao; + else + *rdata = 0; + } else { + *rdata = 0; + } + } + return rstring; +} + +QT_END_NAMESPACE + +#endif // QT_NO_BIG_CODECS +#endif // QT_NO_CODECS diff --git a/src/corelib/codecs/qfontlaocodec_p.h b/src/corelib/codecs/qfontlaocodec_p.h new file mode 100644 index 0000000000..7d0c957f27 --- /dev/null +++ b/src/corelib/codecs/qfontlaocodec_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTLAOCODEC_P_H +#define QFONTLAOCODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qfontencodings_x11.cpp and qfont_x11.cpp. This header file may +// change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_CODECS + +class Q_CORE_EXPORT QFontLaoCodec : public QTextCodec +{ +public: + ~QFontLaoCodec(); + + QByteArray name() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; +}; + +#endif // QT_NO_CODECS + +QT_END_NAMESPACE + +#endif // QFONTLAOCODEC_P_H diff --git a/src/corelib/codecs/qiconvcodec.cpp b/src/corelib/codecs/qiconvcodec.cpp new file mode 100644 index 0000000000..053b3d2834 --- /dev/null +++ b/src/corelib/codecs/qiconvcodec.cpp @@ -0,0 +1,548 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qiconvcodec_p.h" +#include "qtextcodec_p.h" +#include +#include +#include + +#include +#include +#include +#include + +// unistd.h is needed for the _XOPEN_UNIX macro +#include +#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) +# include +#endif + +#if defined(Q_OS_HPUX) +# define NO_BOM +# define UTF16 "ucs2" +#elif defined(Q_OS_AIX) +# define NO_BOM +# define UTF16 "UCS-2" +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) +# define NO_BOM +# if Q_BYTE_ORDER == Q_BIG_ENDIAN +# define UTF16 "UTF-16BE" +# else +# define UTF16 "UTF-16LE" +# endif +#else +# define UTF16 "UTF-16" +#endif + +#if defined(Q_OS_MAC) +#ifndef GNU_LIBICONV +#define GNU_LIBICONV +#endif +typedef iconv_t (*Ptr_iconv_open) (const char*, const char*); +typedef size_t (*Ptr_iconv) (iconv_t, const char **, size_t *, char **, size_t *); +typedef int (*Ptr_iconv_close) (iconv_t); + +static Ptr_iconv_open ptr_iconv_open = 0; +static Ptr_iconv ptr_iconv = 0; +static Ptr_iconv_close ptr_iconv_close = 0; +#endif + +QT_BEGIN_NAMESPACE + +extern bool qt_locale_initialized; + +QIconvCodec::QIconvCodec() + : utf16Codec(0) +{ + utf16Codec = QTextCodec::codecForMib(1015); + Q_ASSERT_X(utf16Codec != 0, + "QIconvCodec::convertToUnicode", + "internal error, UTF-16 codec not found"); + if (!utf16Codec) { + fprintf(stderr, "QIconvCodec::convertToUnicode: internal error, UTF-16 codec not found\n"); + utf16Codec = reinterpret_cast(~0); + } +#if defined(Q_OS_MAC) + if (ptr_iconv_open == 0) { + QLibrary libiconv(QLatin1String("/usr/lib/libiconv")); + libiconv.setLoadHints(QLibrary::ExportExternalSymbolsHint); + + ptr_iconv_open = reinterpret_cast(libiconv.resolve("libiconv_open")); + if (!ptr_iconv_open) + ptr_iconv_open = reinterpret_cast(libiconv.resolve("iconv_open")); + ptr_iconv = reinterpret_cast(libiconv.resolve("libiconv")); + if (!ptr_iconv) + ptr_iconv = reinterpret_cast(libiconv.resolve("iconv")); + ptr_iconv_close = reinterpret_cast(libiconv.resolve("libiconv_close")); + if (!ptr_iconv_close) + ptr_iconv_close = reinterpret_cast(libiconv.resolve("iconv_close")); + + Q_ASSERT_X(ptr_iconv_open && ptr_iconv && ptr_iconv_close, + "QIconvCodec::QIconvCodec()", + "internal error, could not resolve the iconv functions"); + +# undef iconv_open +# define iconv_open ptr_iconv_open +# undef iconv +# define iconv ptr_iconv +# undef iconv_close +# define iconv_close ptr_iconv_close + } +#endif +} + +QIconvCodec::~QIconvCodec() +{ +} + +QIconvCodec::IconvState::IconvState(iconv_t x) + : buffer(array), bufferLen(sizeof array), cd(x) +{ +} + +QIconvCodec::IconvState::~IconvState() +{ + if (cd != reinterpret_cast(-1)) + iconv_close(cd); + if (buffer != array) + delete[] buffer; +} + +void QIconvCodec::IconvState::saveChars(const char *c, int count) +{ + if (count > bufferLen) { + if (buffer != array) + delete[] buffer; + buffer = new char[bufferLen = count]; + } + + memcpy(buffer, c, count); +} + +static void qIconvCodecStateFree(QTextCodec::ConverterState *state) +{ + delete reinterpret_cast(state->d); +} + +Q_GLOBAL_STATIC(QThreadStorage, toUnicodeState) + +QString QIconvCodec::convertToUnicode(const char* chars, int len, ConverterState *convState) const +{ + if (utf16Codec == reinterpret_cast(~0)) + return QString::fromLatin1(chars, len); + + int invalidCount = 0; + int remainingCount = 0; + char *remainingBuffer = 0; + IconvState *temporaryState = 0; + IconvState **pstate; + + if (convState) { + // stateful conversion + pstate = reinterpret_cast(&convState->d); + if (convState->d) { + // restore state + remainingCount = convState->remainingChars; + remainingBuffer = (*pstate)->buffer; + } else { + // first time + convState->flags |= FreeFunction; + QTextCodecUnalignedPointer::encode(convState->state_data, qIconvCodecStateFree); + } + } else { + QThreadStorage *ts = toUnicodeState(); + if (!qt_locale_initialized || !ts) { + // we're running after the Q_GLOBAL_STATIC has been deleted + // or before the QCoreApplication initialization + // bad programmer, no cookie for you + pstate = &temporaryState; + } else { + // stateless conversion -- use thread-local data + pstate = &toUnicodeState()->localData(); + } + } + + if (!*pstate) { + // first time, create the state + iconv_t cd = QIconvCodec::createIconv_t(UTF16, 0); + if (cd == reinterpret_cast(-1)) { + static int reported = 0; + if (!reported++) { + fprintf(stderr, + "QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv_open failed\n"); + } + return QString::fromLatin1(chars, len); + } + + *pstate = new IconvState(cd); + } + + IconvState *state = *pstate; + size_t inBytesLeft = len; + // best case assumption, each byte is converted into one UTF-16 character, plus 2 bytes for the BOM +#ifdef GNU_LIBICONV + // GNU doesn't disagree with POSIX :/ + const char *inBytes = chars; +#else + char *inBytes = const_cast(chars); +#endif + + QByteArray in; + if (remainingCount) { + // we have to prepend the remaining bytes from the previous conversion + inBytesLeft += remainingCount; + in.resize(inBytesLeft); + inBytes = in.data(); + + memcpy(in.data(), remainingBuffer, remainingCount); + memcpy(in.data() + remainingCount, chars, len); + + remainingCount = 0; + } + + size_t outBytesLeft = len * 2 + 2; + QByteArray ba(outBytesLeft, Qt::Uninitialized); + char *outBytes = ba.data(); + do { + size_t ret = iconv(state->cd, &inBytes, &inBytesLeft, &outBytes, &outBytesLeft); + if (ret == (size_t) -1) { + if (errno == E2BIG) { + int offset = ba.size() - outBytesLeft; + ba.resize(ba.size() * 2); + outBytes = ba.data() + offset; + outBytesLeft = ba.size() - offset; + + continue; + } + + if (errno == EILSEQ) { + // conversion stopped because of an invalid character in the sequence + ++invalidCount; + } else if (errno == EINVAL && convState) { + // conversion stopped because the remaining inBytesLeft make up + // an incomplete multi-byte sequence; save them for later + state->saveChars(inBytes, inBytesLeft); + remainingCount = inBytesLeft; + break; + } + + if (errno == EILSEQ || errno == EINVAL) { + // skip the next character + ++inBytes; + --inBytesLeft; + continue; + } + + // some other error + // note, cannot use qWarning() since we are implementing the codecForLocale :) + perror("QIconvCodec::convertToUnicode: using Latin-1 for conversion, iconv failed"); + + if (!convState) { + // reset state + iconv(state->cd, 0, &inBytesLeft, 0, &outBytesLeft); + } + + delete temporaryState; + return QString::fromLatin1(chars, len); + } + } while (inBytesLeft != 0); + + QString s = utf16Codec->toUnicode(ba.constData(), ba.size() - outBytesLeft); + + if (convState) { + convState->invalidChars = invalidCount; + convState->remainingChars = remainingCount; + } else { + // reset state + iconv(state->cd, 0, &inBytesLeft, 0, &outBytesLeft); + } + + delete temporaryState; + return s; +} + +Q_GLOBAL_STATIC(QThreadStorage, fromUnicodeState) + +static bool setByteOrder(iconv_t cd) +{ +#if !defined(NO_BOM) + // give iconv() a BOM + char buf[4]; + ushort bom[] = { QChar::ByteOrderMark }; + + char *outBytes = buf; + char *inBytes = reinterpret_cast(bom); + size_t outBytesLeft = sizeof buf; + size_t inBytesLeft = sizeof bom; + +#if defined(GNU_LIBICONV) + const char **inBytesPtr = const_cast(&inBytes); +#else + char **inBytesPtr = &inBytes; +#endif + + if (iconv(cd, inBytesPtr, &inBytesLeft, &outBytes, &outBytesLeft) == (size_t) -1) { + return false; + } +#endif // NO_BOM + + return true; +} + +QByteArray QIconvCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *convState) const +{ + char *inBytes; + char *outBytes; + size_t inBytesLeft; + +#if defined(GNU_LIBICONV) + const char **inBytesPtr = const_cast(&inBytes); +#else + char **inBytesPtr = &inBytes; +#endif + + IconvState *temporaryState = 0; + QThreadStorage *ts = fromUnicodeState(); + IconvState *&state = (qt_locale_initialized && ts) ? ts->localData() : temporaryState; + if (!state) { + iconv_t cd = QIconvCodec::createIconv_t(0, UTF16); + if (cd != reinterpret_cast(-1)) { + if (!setByteOrder(cd)) { + perror("QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv failed for BOM"); + + iconv_close(cd); + cd = reinterpret_cast(-1); + + return QString(uc, len).toLatin1(); + } + } + state = new IconvState(cd); + } + if (state->cd == reinterpret_cast(-1)) { + static int reported = 0; + if (!reported++) { + fprintf(stderr, + "QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv_open failed\n"); + } + delete temporaryState; + return QString(uc, len).toLatin1(); + } + + size_t outBytesLeft = len; + QByteArray ba(outBytesLeft, Qt::Uninitialized); + outBytes = ba.data(); + + // now feed iconv() the real data + inBytes = const_cast(reinterpret_cast(uc)); + inBytesLeft = len * sizeof(QChar); + + QByteArray in; + if (convState && convState->remainingChars) { + // we have one surrogate char to be prepended + in.resize(sizeof(QChar) + len); + inBytes = in.data(); + + QChar remaining = convState->state_data[0]; + memcpy(in.data(), &remaining, sizeof(QChar)); + memcpy(in.data() + sizeof(QChar), uc, inBytesLeft); + + inBytesLeft += sizeof(QChar); + convState->remainingChars = 0; + } + + int invalidCount = 0; + while (inBytesLeft != 0) { + if (iconv(state->cd, inBytesPtr, &inBytesLeft, &outBytes, &outBytesLeft) == (size_t) -1) { + if (errno == EINVAL && convState) { + // buffer ends in a surrogate + Q_ASSERT(inBytesLeft == 2); + convState->remainingChars = 1; + convState->state_data[0] = uc[len - 1].unicode(); + break; + } + + switch (errno) { + case EILSEQ: + ++invalidCount; + // fall through + case EINVAL: + { + inBytes += sizeof(QChar); + inBytesLeft -= sizeof(QChar); + break; + } + case E2BIG: + { + int offset = ba.size() - outBytesLeft; + ba.resize(ba.size() * 2); + outBytes = ba.data() + offset; + outBytesLeft = ba.size() - offset; + break; + } + default: + { + // note, cannot use qWarning() since we are implementing the codecForLocale :) + perror("QIconvCodec::convertFromUnicode: using Latin-1 for conversion, iconv failed"); + + // reset to initial state + iconv(state->cd, 0, &inBytesLeft, 0, &outBytesLeft); + + delete temporaryState; + return QString(uc, len).toLatin1(); + } + } + } + } + + // reset to initial state + iconv(state->cd, 0, &inBytesLeft, 0, &outBytesLeft); + setByteOrder(state->cd); + + ba.resize(ba.size() - outBytesLeft); + + if (convState) + convState->invalidChars = invalidCount; + + delete temporaryState; + return ba; +} + +QByteArray QIconvCodec::name() const +{ + return "System"; +} + +int QIconvCodec::mibEnum() const +{ + return 0; +} + +iconv_t QIconvCodec::createIconv_t(const char *to, const char *from) +{ + Q_ASSERT((to == 0 && from != 0) || (to != 0 && from == 0)); + + iconv_t cd = (iconv_t) -1; +#if defined(__GLIBC__) || defined(GNU_LIBICONV) + // both GLIBC and libgnuiconv will use the locale's encoding if from or to is an empty string + static const char empty_codeset[] = ""; + const char *codeset = empty_codeset; + cd = iconv_open(to ? to : codeset, from ? from : codeset); +#else + char *codeset = 0; +#endif + +#if defined(_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) + if (cd == (iconv_t) -1) { + codeset = nl_langinfo(CODESET); + if (codeset) + cd = iconv_open(to ? to : codeset, from ? from : codeset); + } +#endif + + if (cd == (iconv_t) -1) { + // Very poorly defined and followed standards causes lots of + // code to try to get all the cases... This logic is + // duplicated in QTextCodec, so if you change it here, change + // it there too. + + // Try to determine locale codeset from locale name assigned to + // LC_CTYPE category. + + // First part is getting that locale name. First try setlocale() which + // definitely knows it, but since we cannot fully trust it, get ready + // to fall back to environment variables. + char * ctype = qstrdup(setlocale(LC_CTYPE, 0)); + + // Get the first nonempty value from $LC_ALL, $LC_CTYPE, and $LANG + // environment variables. + char * lang = qstrdup(qgetenv("LC_ALL").constData()); + if (!lang || lang[0] == 0 || strcmp(lang, "C") == 0) { + if (lang) delete [] lang; + lang = qstrdup(qgetenv("LC_CTYPE").constData()); + } + if (!lang || lang[0] == 0 || strcmp(lang, "C") == 0) { + if (lang) delete [] lang; + lang = qstrdup(qgetenv("LANG").constData()); + } + + // Now try these in order: + // 1. CODESET from ctype if it contains a .CODESET part (e.g. en_US.ISO8859-15) + // 2. CODESET from lang if it contains a .CODESET part + // 3. ctype (maybe the locale is named "ISO-8859-1" or something) + // 4. locale (ditto) + // 5. check for "@euro" + + // 1. CODESET from ctype if it contains a .CODESET part (e.g. en_US.ISO8859-15) + codeset = ctype ? strchr(ctype, '.') : 0; + if (codeset && *codeset == '.') { + ++codeset; + cd = iconv_open(to ? to : codeset, from ? from : codeset); + } + + // 2. CODESET from lang if it contains a .CODESET part + codeset = lang ? strchr(lang, '.') : 0; + if (cd == (iconv_t) -1 && codeset && *codeset == '.') { + ++codeset; + cd = iconv_open(to ? to : codeset, from ? from : codeset); + } + + // 3. ctype (maybe the locale is named "ISO-8859-1" or something) + if (cd == (iconv_t) -1 && ctype && *ctype != 0 && strcmp (ctype, "C") != 0) + cd = iconv_open(to ? to : ctype, from ? from : ctype); + + + // 4. locale (ditto) + if (cd == (iconv_t) -1 && lang && *lang != 0) + cd = iconv_open(to ? to : lang, from ? from : lang); + + // 5. "@euro" + if ((cd == (iconv_t) -1 && ctype && strstr(ctype, "@euro")) || (lang && strstr(lang, "@euro"))) + cd = iconv_open(to ? to : "ISO8859-15", from ? from : "ISO8859-15"); + + delete [] ctype; + delete [] lang; + } + + return cd; +} + +QT_END_NAMESPACE diff --git a/src/corelib/codecs/qiconvcodec_p.h b/src/corelib/codecs/qiconvcodec_p.h new file mode 100644 index 0000000000..131347ca1b --- /dev/null +++ b/src/corelib/codecs/qiconvcodec_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QICONVCODEC_P_H +#define QICONVCODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtextcodec.h" + +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) + +#ifdef Q_OS_MAC +typedef void * iconv_t; +#else +#include +#endif + +QT_BEGIN_NAMESPACE + +class QIconvCodec: public QTextCodec +{ +private: + mutable QTextCodec *utf16Codec; + +public: + QIconvCodec(); + ~QIconvCodec(); + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + + QByteArray name() const; + int mibEnum() const; + + static iconv_t createIconv_t(const char *to, const char *from); + + class IconvState + { + public: + IconvState(iconv_t x); + ~IconvState(); + char *buffer; + int bufferLen; + iconv_t cd; + + char array[8]; + + void saveChars(const char *c, int count); + }; +}; + +QT_END_NAMESPACE + +#endif // Q_OS_UNIX && !QT_NO_ICONV && !QT_BOOTSTRAPPED + +#endif // QICONVCODEC_P_H diff --git a/src/corelib/codecs/qisciicodec.cpp b/src/corelib/codecs/qisciicodec.cpp new file mode 100644 index 0000000000..f7b450b4e4 --- /dev/null +++ b/src/corelib/codecs/qisciicodec.cpp @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qisciicodec_p.h" +#include "qlist.h" + +#ifndef QT_NO_CODECS + +QT_BEGIN_NAMESPACE + +/*! + \class QIsciiCodec + \brief The QIsciiCodec class provides conversion to and from the ISCII encoding. + + \internal +*/ + + +struct Codecs { + const char name[10]; + ushort base; +}; + +static const Codecs codecs [] = { + { "Iscii-Dev", 0x900 }, + { "Iscii-Bng", 0x980 }, + { "Iscii-Pnj", 0xa00 }, + { "Iscii-Gjr", 0xa80 }, + { "Iscii-Ori", 0xb00 }, + { "Iscii-Tml", 0xb80 }, + { "Iscii-Tlg", 0xc00 }, + { "Iscii-Knd", 0xc80 }, + { "Iscii-Mlm", 0xd00 } +}; + +QIsciiCodec::~QIsciiCodec() +{ +} + +QByteArray QIsciiCodec::name() const +{ + return codecs[idx].name; +} + +int QIsciiCodec::mibEnum() const +{ + /* There is no MIBEnum for Iscii */ + return -3000-idx; +} + +static const uchar inv = 0xFF; + +/* iscii range from 0xa0 - 0xff */ +static const uchar iscii_to_uni_table[0x60] = { + 0x00, 0x01, 0x02, 0x03, + 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0e, + 0x0f, 0x20, 0x0d, 0x12, + + 0x13, 0x14, 0x11, 0x15, + 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, + + 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, 0x5f, 0x30, + + 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, + 0x39, inv, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, + + 0x46, 0x47, 0x48, 0x45, + 0x4a, 0x4b, 0x4c, 0x49, + 0x4d, 0x3c, 0x64, 0x00, + 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static const uchar uni_to_iscii_table[0x80] = { + 0x00, 0xa1, 0xa2, 0xa3, + 0x00, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, + 0x00, 0xae, 0xab, 0xac, + + 0xad, 0xb2, 0xaf, 0xb0, + 0xb1, 0xb3, 0xb4, 0xb5, + 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, + + 0xbe, 0xbf, 0xc0, 0xc1, + 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, + + 0xcf, 0xd0, 0xd1, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, + 0xd7, 0xd8, 0x00, 0x00, + 0xe9, 0x00, 0xda, 0xdb, + + 0xdc, 0xdd, 0xde, 0xdf, + 0x00, 0xe3, 0xe0, 0xe1, + 0xe2, 0xe7, 0xe4, 0xe5, + 0xe6, 0xe8, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04, // decomposable into the uc codes listed here + nukta + 0x05, 0x06, 0x07, 0xce, + + 0x00, 0x00, 0x00, 0x00, + 0xea, 0x08, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf8, 0xf9, 0xfa, + + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static const uchar uni_to_iscii_pairs[] = { + 0x00, 0x00, + 0x15, 0x3c, // 0x958 + 0x16, 0x3c, // 0x959 + 0x17, 0x3c, // 0x95a + 0x1c, 0x3c, // 0x95b + 0x21, 0x3c, // 0x95c + 0x22, 0x3c, // 0x95d + 0x2b, 0x3c, // 0x95e + 0x64, 0x64 // 0x965 +}; + + +QByteArray QIsciiCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + char replacement = '?'; + bool halant = false; + if (state) { + if (state->flags & ConvertInvalidToNull) + replacement = 0; + halant = state->state_data[0]; + } + int invalid = 0; + + QByteArray result(2 * len, Qt::Uninitialized); //worst case + + uchar *ch = reinterpret_cast(result.data()); + + const int base = codecs[idx].base; + + for (int i =0; i < len; ++i) { + const ushort codePoint = uc[i].unicode(); + + /* The low 7 bits of ISCII is plain ASCII. However, we go all the + * way up to 0xA0 such that we can roundtrip with convertToUnicode()'s + * behavior. */ + if(codePoint < 0xA0) { + *ch++ = static_cast(codePoint); + continue; + } + + const int pos = codePoint - base; + if (pos > 0 && pos < 0x80) { + uchar iscii = uni_to_iscii_table[pos]; + if (iscii > 0x80) { + *ch++ = iscii; + } else if (iscii) { + const uchar *pair = uni_to_iscii_pairs + 2*iscii; + *ch++ = *pair++; + *ch++ = *pair++; + } else { + *ch++ = replacement; + ++invalid; + } + } else { + if (uc[i].unicode() == 0x200c) { // ZWNJ + if (halant) + // Consonant Halant ZWNJ -> Consonant Halant Halant + *ch++ = 0xe8; + } else if (uc[i].unicode() == 0x200d) { // ZWJ + if (halant) + // Consonant Halant ZWJ -> Consonant Halant Nukta + *ch++ = 0xe9; + } else { + *ch++ = replacement; + ++invalid; + } + } + halant = (pos == 0x4d); + } + result.truncate(ch - (uchar *)result.data()); + + if (state) { + state->invalidChars += invalid; + state->state_data[0] = halant; + } + return result; +} + +QString QIsciiCodec::convertToUnicode(const char* chars, int len, ConverterState *state) const +{ + bool halant = false; + if (state) { + halant = state->state_data[0]; + } + + QString result(len, Qt::Uninitialized); + QChar *uc = result.data(); + + const int base = codecs[idx].base; + + for (int i = 0; i < len; ++i) { + ushort ch = (uchar) chars[i]; + if (ch < 0xa0) + *uc++ = ch; + else { + ushort c = iscii_to_uni_table[ch - 0xa0]; + if (halant && (c == inv || c == 0xe9)) { + // Consonant Halant inv -> Consonant Halant ZWJ + // Consonant Halant Nukta -> Consonant Halant ZWJ + *uc++ = QChar(0x200d); + } else if (halant && c == 0xe8) { + // Consonant Halant Halant -> Consonant Halant ZWNJ + *uc++ = QChar(0x200c); + } else { + *uc++ = QChar(c+base); + } + } + halant = ((uchar)chars[i] == 0xe8); + } + result.resize(uc - result.unicode()); + + if (state) { + state->state_data[0] = halant; + } + return result; +} + +QT_END_NAMESPACE + +#endif // QT_NO_CODECS diff --git a/src/corelib/codecs/qisciicodec_p.h b/src/corelib/codecs/qisciicodec_p.h new file mode 100644 index 0000000000..024670c527 --- /dev/null +++ b/src/corelib/codecs/qisciicodec_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QISCIICODEC_P_H +#define QISCIICODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_CODECS + +class QIsciiCodec : public QTextCodec { +public: + explicit QIsciiCodec(int i) : idx(i) {} + ~QIsciiCodec(); + + QByteArray name() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + +private: + int idx; +}; + +#endif // QT_NO_CODECS + +QT_END_NAMESPACE + +#endif // QISCIICODEC_P_H diff --git a/src/corelib/codecs/qlatincodec.cpp b/src/corelib/codecs/qlatincodec.cpp new file mode 100644 index 0000000000..20e59533a2 --- /dev/null +++ b/src/corelib/codecs/qlatincodec.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlatincodec_p.h" +#include "qlist.h" + +#ifndef QT_NO_TEXTCODEC + +QT_BEGIN_NAMESPACE + +QLatin1Codec::~QLatin1Codec() +{ +} + +QString QLatin1Codec::convertToUnicode(const char *chars, int len, ConverterState *) const +{ + if (chars == 0) + return QString(); + + return QString::fromLatin1(chars, len); +} + + +QByteArray QLatin1Codec::convertFromUnicode(const QChar *ch, int len, ConverterState *state) const +{ + const char replacement = (state && state->flags & ConvertInvalidToNull) ? 0 : '?'; + QByteArray r(len, Qt::Uninitialized); + char *d = r.data(); + int invalid = 0; + for (int i = 0; i < len; ++i) { + if (ch[i] > 0xff) { + d[i] = replacement; + ++invalid; + } else { + d[i] = (char)ch[i].cell(); + } + } + if (state) { + state->invalidChars += invalid; + } + return r; +} + +QByteArray QLatin1Codec::name() const +{ + return "ISO-8859-1"; +} + +QList QLatin1Codec::aliases() const +{ + QList list; + list << "latin1" + << "CP819" + << "IBM819" + << "iso-ir-100" + << "csISOLatin1"; + return list; +} + + +int QLatin1Codec::mibEnum() const +{ + return 4; +} + + +QLatin15Codec::~QLatin15Codec() +{ +} + +QString QLatin15Codec::convertToUnicode(const char* chars, int len, ConverterState *) const +{ + if (chars == 0) + return QString(); + + QString str = QString::fromLatin1(chars, len); + QChar *uc = str.data(); + while(len--) { + switch(uc->unicode()) { + case 0xa4: + *uc = 0x20ac; + break; + case 0xa6: + *uc = 0x0160; + break; + case 0xa8: + *uc = 0x0161; + break; + case 0xb4: + *uc = 0x017d; + break; + case 0xb8: + *uc = 0x017e; + break; + case 0xbc: + *uc = 0x0152; + break; + case 0xbd: + *uc = 0x0153; + break; + case 0xbe: + *uc = 0x0178; + break; + default: + break; + } + uc++; + } + return str; +} + +QByteArray QLatin15Codec::convertFromUnicode(const QChar *in, int length, ConverterState *state) const +{ + const char replacement = (state && state->flags & ConvertInvalidToNull) ? 0 : '?'; + QByteArray r(length, Qt::Uninitialized); + char *d = r.data(); + int invalid = 0; + for (int i = 0; i < length; ++i) { + uchar c; + ushort uc = in[i].unicode(); + if (uc < 0x0100) { + if (uc > 0xa3) { + switch(uc) { + case 0xa4: + case 0xa6: + case 0xa8: + case 0xb4: + case 0xb8: + case 0xbc: + case 0xbd: + case 0xbe: + c = replacement; + ++invalid; + break; + default: + c = (unsigned char) uc; + break; + } + } else { + c = (unsigned char) uc; + } + } else { + if (uc == 0x20ac) + c = 0xa4; + else if ((uc & 0xff00) == 0x0100) { + switch(uc) { + case 0x0160: + c = 0xa6; + break; + case 0x0161: + c = 0xa8; + break; + case 0x017d: + c = 0xb4; + break; + case 0x017e: + c = 0xb8; + break; + case 0x0152: + c = 0xbc; + break; + case 0x0153: + c = 0xbd; + break; + case 0x0178: + c = 0xbe; + break; + default: + c = replacement; + ++invalid; + } + } else { + c = replacement; + ++invalid; + } + } + d[i] = (char)c; + } + if (state) { + state->remainingChars = 0; + state->invalidChars += invalid; + } + return r; +} + + +QByteArray QLatin15Codec::name() const +{ + return "ISO-8859-15"; +} + +QList QLatin15Codec::aliases() const +{ + QList list; + list << "latin9"; + return list; +} + +int QLatin15Codec::mibEnum() const +{ + return 111; +} + +QT_END_NAMESPACE + +#endif // QT_NO_TEXTCODEC diff --git a/src/corelib/codecs/qlatincodec_p.h b/src/corelib/codecs/qlatincodec_p.h new file mode 100644 index 0000000000..fffc1fa983 --- /dev/null +++ b/src/corelib/codecs/qlatincodec_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLATINCODEC_P_H +#define QLATINCODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_TEXTCODEC + +class QLatin1Codec : public QTextCodec +{ +public: + ~QLatin1Codec(); + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + + + +class QLatin15Codec: public QTextCodec +{ +public: + ~QLatin15Codec(); + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + +#endif // QT_NO_TEXTCODEC + +QT_END_NAMESPACE + +#endif // QLATINCODEC_P_H diff --git a/src/corelib/codecs/qsimplecodec.cpp b/src/corelib/codecs/qsimplecodec.cpp new file mode 100644 index 0000000000..abbbc8d650 --- /dev/null +++ b/src/corelib/codecs/qsimplecodec.cpp @@ -0,0 +1,735 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimplecodec_p.h" +#include "qlist.h" + +#ifndef QT_NO_TEXTCODEC + +QT_BEGIN_NAMESPACE + +#define LAST_MIB 2004 + +static const struct { + const char *mime; + const char *aliases[7]; + int mib; + quint16 values[128]; +} unicodevalues[QSimpleTextCodec::numSimpleCodecs] = { +#ifndef Q_OS_SYMBIAN + // from RFC 1489, ftp://ftp.isi.edu/in-notes/rfc1489.txt + { "KOI8-R", { "csKOI8R", 0 }, 2084, + { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219/**/, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A } }, + // /**/ - The BULLET OPERATOR is confused. Some people think + // it should be 0x2022 (BULLET). + + // from RFC 2319, ftp://ftp.isi.edu/in-notes/rfc2319.txt + { "KOI8-U", { "KOI8-RU", 0 }, 2088, + { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A } }, + + // next bits generated from tables on the Unicode 2.0 CD. we can + // use these tables since this is part of the transition to using + // unicode everywhere in qt. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo 0x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; for a in 8859-* ; do (awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a ; cat /tmp/digits) | sort | uniq -w4 | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done + + // then I inserted the files manually. + { "ISO-8859-2", {"latin2", "iso-ir-101", "csISOLatin2", 0 }, 5, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "ISO-8859-3", { "latin3", "iso-ir-109", "csISOLatin3", 0 }, 6, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9} }, + { "ISO-8859-4", { "latin4", "iso-ir-110", "csISOLatin4", 0 }, 7, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9} }, + { "ISO-8859-5", { "cyrillic", "iso-ir-144", "csISOLatinCyrillic", 0 }, 8, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F} }, + { "ISO-8859-6", { "ISO-8859-6-I", "ECMA-114", "ASMO-708", "arabic", "iso-ir-127", "csISOLatinArabic", 0 }, 82, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A4, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x060C, 0x00AD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0x061B, 0xFFFD, 0xFFFD, 0xFFFD, 0x061F, + 0xFFFD, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO-8859-7", { "ECMA-118", "greek", "iso-ir-126", "csISOLatinGreek", 0 }, 10, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "ISO-8859-8", { "ISO 8859-8-I", "iso-ir-138", "hebrew", "csISOLatinHebrew", 0 }, 85, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO-8859-9", { "iso-ir-148", "latin5", "csISOLatin5", 0 }, 12, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "ISO-8859-10", { "iso-ir-157", "latin6", "ISO-8859-10:1992", "csISOLatin6", 0 }, 13, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138} }, + { "ISO-8859-13", { 0 }, 109, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019} }, + { "ISO-8859-14", { "iso-ir-199", "latin8", "iso-celtic", 0 }, 110, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF} }, +#endif + { "ISO-8859-16", { "iso-ir-226", "latin10", 0 }, 112, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B, + 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7, + 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A, + 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, + 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF} }, + + // next bits generated again from tables on the Unicode 3.0 CD. + + // $ for a in CP* ; do (awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a) | sort | sed -e 's/#UNDEF.*$/0xFFFD/' | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done +#ifndef Q_OS_SYMBIAN + { "IBM850", { "CP850", "csPC850Multilingual", 0 }, 2009, + { 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0} }, + { "IBM874", { "CP874", 0 }, -874, //### what is the mib? + { 0x20AC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2026, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, +#endif //Q_OS_SYMBIAN + { "IBM866", { "CP866", "csIBM866", 0 }, 2086, + { 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0} }, + +#ifndef Q_OS_SYMBIAN + { "windows-1250", { "CP1250", 0 }, 2250, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "windows-1251", { "CP1251", 0 }, 2251, + { 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F} }, + { "windows-1252", { "CP1252", 0 }, 2252, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + { "windows-1253", {"CP1253", 0 }, 2253, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "windows-1254", { "CP1254", 0 }, 2254, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "windows-1255", { "CP1255", 0 }, 2255, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD} }, + { "windows-1256", { "CP1256", 0 }, 2256, + { 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2} }, + { "windows-1257", { "CP1257", 0 }, 2257, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9} }, + { "windows-1258", { "CP1258", 0 }, 2258, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF} }, + +#endif + { "Apple Roman", { "macintosh", "MacRoman", 0 }, -168, + { 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7} }, + + // This one is based on the charmap file + // /usr/share/i18n/charmaps/SAMI-WS2.gz, which is manually adapted + // to this format by Boerre Gaup + { "WINSAMI2", { "WS2", 0 }, -165, + { 0x20AC, 0xFFFD, 0x010C, 0x0192, 0x010D, 0x01B7, 0x0292, 0x01EE, + 0x01EF, 0x0110, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0111, 0x01E6, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x01E7, 0x01E4, 0x00A3, 0x00A4, 0x01E5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x021E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x021F, + 0x00B0, 0x00B1, 0x01E8, 0x01E9, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x014A, 0x014B, 0x0166, 0x00BB, 0x0167, 0x00BD, 0x017D, 0x017E, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + +#ifndef Q_OS_SYMBIAN + // this one is generated from the charmap file located in /usr/share/i18n/charmaps + // on most Linux distributions. The thai character set tis620 is byte by byte equivalent + // to iso8859-11, so we name it 8859-11 here, but recognise the name tis620 too. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; (cut -c25- < TIS-620 ; cat /tmp/digits) | awk '/^x[89ABCDEF]/{ print $1, $2 }' | sed -e 's///' | sort | uniq -w4 | cut -c5- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/tis-620 + { "TIS-620", { "ISO 8859-11", 0 }, 2259, // Thai character set mib enum taken from tis620 (which is byte by byte equivalent) + { 0x20AC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2026, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD } }, + +#endif + /* + Name: hp-roman8 [HP-PCL5,RFC1345,KXS2] + MIBenum: 2004 + Source: LaserJet IIP Printer User's Manual, + HP part no 33471-90901, Hewlet-Packard, June 1989. + Alias: roman8 + Alias: r8 + Alias: csHPRoman8 + */ + { "roman8", { "hp-roman8", "csHPRoman8", 0 }, 2004, + { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x00C0, 0x00C2, 0x00C8, 0x00CA, 0x00CB, 0x00CE, 0x00CF, + 0x00B4, 0x02CB, 0x02C6, 0x00A8, 0x02DC, 0x00D9, 0x00DB, 0x20A4, + 0x00AF, 0x00DD, 0x00FD, 0x00B0, 0x00C7, 0x00E7, 0x00D1, 0x00F1, + 0x00A1, 0x00BF, 0x00A4, 0x00A3, 0x00A5, 0x00A7, 0x0192, 0x00A2, + 0x00E2, 0x00EA, 0x00F4, 0x00FB, 0x00E1, 0x00E9, 0x00F3, 0x00FA, + 0x00E0, 0x00E8, 0x00F2, 0x00F9, 0x00E4, 0x00EB, 0x00F6, 0x00FC, + 0x00C5, 0x00EE, 0x00D8, 0x00C6, 0x00E5, 0x00ED, 0x00F8, 0x00E6, + 0x00C4, 0x00EC, 0x00D6, 0x00DC, 0x00C9, 0x00EF, 0x00DF, 0x00D4, + 0x00C1, 0x00C3, 0x00E3, 0x00D0, 0x00F0, 0x00CD, 0x00CC, 0x00D3, + 0x00D2, 0x00D5, 0x00F5, 0x0160, 0x0161, 0x00DA, 0x0178, 0x00FF, + 0x00DE, 0x00FE, 0x00B7, 0x00B5, 0x00B6, 0x00BE, 0x2014, 0x00BC, + 0x00BD, 0x00AA, 0x00BA, 0x00AB, 0x25A0, 0x00BB, 0x00B1, 0xFFFD } } + + // if you add more chacater sets at the end, change LAST_MIB above +}; + +QSimpleTextCodec::QSimpleTextCodec(int i) : forwardIndex(i), reverseMap(0) +{ +} + + +QSimpleTextCodec::~QSimpleTextCodec() +{ + delete reverseMap; +} + +static QByteArray *buildReverseMap(int forwardIndex) +{ + QByteArray *map = new QByteArray(); + int m = 0; + int i = 0; + while(i < 128) { + if (unicodevalues[forwardIndex].values[i] > m && + unicodevalues[forwardIndex].values[i] < 0xfffd) + m = unicodevalues[forwardIndex].values[i]; + i++; + } + m++; + map->resize(m); + for(i = 0; i < 128 && i < m; i++) + (*map)[i] = (char)i; + for(;i < m; i++) + (*map)[i] = 0; + for(i=128; i<256; i++) { + int u = unicodevalues[forwardIndex].values[i-128]; + if (u < m) + (*map)[u] = (char)(unsigned char)(i); + } + return map; +} + +QString QSimpleTextCodec::convertToUnicode(const char* chars, int len, ConverterState *) const +{ + if (len <= 0 || chars == 0) + return QString(); + + const unsigned char * c = (const unsigned char *)chars; + + QString r(len, Qt::Uninitialized); + QChar* uc = r.data(); + + for (int i = 0; i < len; i++) { + if (c[i] > 127) + uc[i] = unicodevalues[forwardIndex].values[c[i]-128]; + else + uc[i] = QLatin1Char(c[i]); + } + return r; +} + +QByteArray QSimpleTextCodec::convertFromUnicode(const QChar *in, int length, ConverterState *state) const +{ + const char replacement = (state && state->flags & ConvertInvalidToNull) ? 0 : '?'; + int invalid = 0; + + if (!reverseMap){ + QByteArray *tmp = buildReverseMap(this->forwardIndex); + if (!reverseMap.testAndSetOrdered(0, tmp)) + delete tmp; + } + + QByteArray r(length, Qt::Uninitialized); + int i = length; + int u; + const QChar* ucp = in; + unsigned char* rp = (unsigned char *)r.data(); + const unsigned char* rmp = (const unsigned char *)reverseMap->constData(); + int rmsize = (int) reverseMap->size(); + while(i--) + { + u = ucp->unicode(); + if (u < 128) { + *rp = (char)u; + } else { + *rp = ((u < rmsize) ? (*(rmp+u)) : 0); + if (*rp == 0) { + *rp = replacement; + ++invalid; + } + } + rp++; + ucp++; + } + + if (state) { + state->invalidChars += invalid; + } + return r; +} + +QByteArray QSimpleTextCodec::name() const +{ + return unicodevalues[forwardIndex].mime; +} + +QList QSimpleTextCodec::aliases() const +{ + QList list; + const char * const*a = unicodevalues[forwardIndex].aliases; + while (*a) { + list << *a; + ++a; + } + return list; +} + +int QSimpleTextCodec::mibEnum() const +{ + return unicodevalues[forwardIndex].mib; +} + +QT_END_NAMESPACE + +#endif // QT_NO_TEXTCODEC diff --git a/src/corelib/codecs/qsimplecodec_p.h b/src/corelib/codecs/qsimplecodec_p.h new file mode 100644 index 0000000000..ea771a68b7 --- /dev/null +++ b/src/corelib/codecs/qsimplecodec_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSIMPLECODEC_P_H +#define QSIMPLECODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_TEXTCODEC + +template class QAtomicPointer; + +class QSimpleTextCodec: public QTextCodec +{ +public: +#ifdef Q_OS_SYMBIAN + enum { numSimpleCodecs = 5 }; +#else + enum { numSimpleCodecs = 30 }; +#endif + explicit QSimpleTextCodec(int); + ~QSimpleTextCodec(); + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + + QByteArray name() const; + QList aliases() const; + int mibEnum() const; + +private: + int forwardIndex; + mutable QAtomicPointer reverseMap; +}; + +#endif // QT_NO_TEXTCODEC + +QT_END_NAMESPACE + +#endif // QSIMPLECODEC_P_H diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp new file mode 100644 index 0000000000..3c3d39ed99 --- /dev/null +++ b/src/corelib/codecs/qtextcodec.cpp @@ -0,0 +1,1878 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qtextcodec.h" +#include "qtextcodec_p.h" + +#ifndef QT_NO_TEXTCODEC + +#include "qlist.h" +#include "qfile.h" +#ifndef QT_NO_LIBRARY +# include "qcoreapplication.h" +# include "qtextcodecplugin.h" +# include "private/qfactoryloader_p.h" +#endif +#include "qstringlist.h" + +#ifdef Q_OS_UNIX +# include "qiconvcodec_p.h" +#endif + +#include "qutfcodec_p.h" +#include "qsimplecodec_p.h" +#include "qlatincodec_p.h" +#ifndef QT_NO_CODECS +# include "qtsciicodec_p.h" +# include "qisciicodec_p.h" +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) +# if defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) +// no iconv(3) support, must build all codecs into the library +# include "../../plugins/codecs/cn/qgb18030codec.h" +# include "../../plugins/codecs/jp/qeucjpcodec.h" +# include "../../plugins/codecs/jp/qjiscodec.h" +# include "../../plugins/codecs/jp/qsjiscodec.h" +# include "../../plugins/codecs/kr/qeuckrcodec.h" +# include "../../plugins/codecs/tw/qbig5codec.h" +# endif // QT_NO_ICONV +# if defined(Q_WS_X11) && !defined(QT_BOOTSTRAPPED) +# include "qfontlaocodec_p.h" +# include "../../plugins/codecs/jp/qfontjpcodec.h" +# endif +#endif // QT_NO_SYMBIAN +#endif // QT_NO_CODECS +#include "qlocale.h" +#include "qmutex.h" +#include "qhash.h" + +#include +#include +#include +#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) +#include +#endif + +#if defined(Q_OS_WINCE) +# define QT_NO_SETLOCALE +#endif + +#ifdef Q_OS_SYMBIAN +#include "qtextcodec_symbian.cpp" +#endif + + +// enabling this is not exception safe! +// #define Q_DEBUG_TEXTCODEC + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QTextCodecFactoryInterface_iid, QLatin1String("/codecs"))) +#endif + +//Cache for QTextCodec::codecForName and codecForMib. +typedef QHash QTextCodecCache; +Q_GLOBAL_STATIC(QTextCodecCache, qTextCodecCache) + + +static char qtolower(register char c) +{ if (c >= 'A' && c <= 'Z') return c + 0x20; return c; } +static bool qisalnum(register char c) +{ return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } + +static bool nameMatch(const QByteArray &name, const QByteArray &test) +{ + // if they're the same, return a perfect score + if (qstricmp(name, test) == 0) + return true; + + const char *n = name.constData(); + const char *h = test.constData(); + + // if the letters and numbers are the same, we have a match + while (*n != '\0') { + if (qisalnum(*n)) { + for (;;) { + if (*h == '\0') + return false; + if (qisalnum(*h)) + break; + ++h; + } + if (qtolower(*n) != qtolower(*h)) + return false; + ++h; + } + ++n; + } + while (*h && !qisalnum(*h)) + ++h; + return (*h == '\0'); +} + + +static QTextCodec *createForName(const QByteArray &name) +{ +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) + QFactoryLoader *l = loader(); + QStringList keys = l->keys(); + for (int i = 0; i < keys.size(); ++i) { + if (nameMatch(name, keys.at(i).toLatin1())) { + QString realName = keys.at(i); + if (QTextCodecFactoryInterface *factory + = qobject_cast(l->instance(realName))) { + return factory->create(realName); + } + } + } +#else + Q_UNUSED(name); +#endif + return 0; +} + +static QTextCodec *createForMib(int mib) +{ +#ifndef QT_NO_TEXTCODECPLUGIN + QString name = QLatin1String("MIB: ") + QString::number(mib); + if (QTextCodecFactoryInterface *factory + = qobject_cast(loader()->instance(name))) + return factory->create(name); +#else + Q_UNUSED(mib); +#endif + return 0; +} + +static QList *all = 0; +#ifdef Q_DEBUG_TEXTCODEC +static bool destroying_is_ok = false; +#endif + +static QTextCodec *localeMapper = 0; +QTextCodec *QTextCodec::cftr = 0; + + +class QTextCodecCleanup +{ +public: + ~QTextCodecCleanup(); +}; + +/* + Deletes all the created codecs. This destructor is called just + before exiting to delete any QTextCodec objects that may be lying + around. +*/ +QTextCodecCleanup::~QTextCodecCleanup() +{ + if (!all) + return; + +#ifdef Q_DEBUG_TEXTCODEC + destroying_is_ok = true; +#endif + + for (QList::const_iterator it = all->constBegin() + ; it != all->constEnd(); ++it) { + delete *it; + } + delete all; + all = 0; + localeMapper = 0; + +#ifdef Q_DEBUG_TEXTCODEC + destroying_is_ok = false; +#endif +} + +Q_GLOBAL_STATIC(QTextCodecCleanup, createQTextCodecCleanup) + +bool QTextCodec::validCodecs() +{ +#ifdef Q_OS_SYMBIAN + // If we don't have a trap handler, we're outside of the main() function, + // ie. in global constructors or destructors. Don't use codecs in this + // case as it would lead to crashes because we don't have a cleanup stack on Symbian + return (User::TrapHandler() != NULL); +#else + return true; +#endif +} + + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +class QWindowsLocalCodec: public QTextCodec +{ +public: + QWindowsLocalCodec(); + ~QWindowsLocalCodec(); + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + QString convertToUnicodeCharByChar(const char *chars, int length, ConverterState *state) const; + + QByteArray name() const; + int mibEnum() const; + +}; + +QWindowsLocalCodec::QWindowsLocalCodec() +{ +} + +QWindowsLocalCodec::~QWindowsLocalCodec() +{ +} + +QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, ConverterState *state) const +{ + const char *mb = chars; + int mblen = length; + + if (!mb || !mblen) + return QString(); + + const int wclen_auto = 4096; + wchar_t wc_auto[wclen_auto]; + int wclen = wclen_auto; + wchar_t *wc = wc_auto; + int len; + QString sp; + bool prepend = false; + char state_data = 0; + int remainingChars = 0; + + //save the current state information + if (state) { + state_data = (char)state->state_data[0]; + remainingChars = state->remainingChars; + } + + //convert the pending charcter (if available) + if (state && remainingChars) { + char prev[3] = {0}; + prev[0] = state_data; + prev[1] = mb[0]; + remainingChars = 0; + len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, + prev, 2, wc, wclen); + if (len) { + prepend = true; + sp.append(QChar(wc[0])); + mb++; + mblen--; + wc[0] = 0; + } + } + + while (!(len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, + mb, mblen, wc, wclen))) { + int r = GetLastError(); + if (r == ERROR_INSUFFICIENT_BUFFER) { + if (wc != wc_auto) { + qWarning("MultiByteToWideChar: Size changed"); + break; + } else { + wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, + mb, mblen, 0, 0); + wc = new wchar_t[wclen]; + // and try again... + } + } else if (r == ERROR_NO_UNICODE_TRANSLATION) { + //find the last non NULL character + while (mblen > 1 && !(mb[mblen-1])) + mblen--; + //check whether, we hit an invalid character in the middle + if ((mblen <= 1) || (remainingChars && state_data)) + return convertToUnicodeCharByChar(chars, length, state); + //Remove the last character and try again... + state_data = mb[mblen-1]; + remainingChars = 1; + mblen--; + } else { + // Fail. + qWarning("MultiByteToWideChar: Cannot convert multibyte text"); + break; + } + } + if (len <= 0) + return QString(); + if (wc[len-1] == 0) // len - 1: we don't want terminator + --len; + + //save the new state information + if (state) { + state->state_data[0] = (char)state_data; + state->remainingChars = remainingChars; + } + QString s((QChar*)wc, len); + if (wc != wc_auto) + delete [] wc; + if (prepend) { + return sp+s; + } + return s; +} + +QString QWindowsLocalCodec::convertToUnicodeCharByChar(const char *chars, int length, ConverterState *state) const +{ + if (!chars || !length) + return QString(); + + int copyLocation = 0; + int extra = 2; + if (state && state->remainingChars) { + copyLocation = state->remainingChars; + extra += copyLocation; + } + int newLength = length + extra; + char *mbcs = new char[newLength]; + //ensure that we have a NULL terminated string + mbcs[newLength-1] = 0; + mbcs[newLength-2] = 0; + memcpy(&(mbcs[copyLocation]), chars, length); + if (copyLocation) { + //copy the last character from the state + mbcs[0] = (char)state->state_data[0]; + state->remainingChars = 0; + } + const char *mb = mbcs; +#ifndef Q_OS_WINCE + const char *next = 0; + QString s; + while((next = CharNextExA(CP_ACP, mb, 0)) != mb) { + wchar_t wc[2] ={0}; + int charlength = next - mb; + int len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, mb, charlength, wc, 2); + if (len>0) { + s.append(QChar(wc[0])); + } else { + int r = GetLastError(); + //check if the character being dropped is the last character + if (r == ERROR_NO_UNICODE_TRANSLATION && mb == (mbcs+newLength -3) && state) { + state->remainingChars = 1; + state->state_data[0] = (char)*mb; + } + } + mb = next; + } +#else + QString s; + int size = mbstowcs(NULL, mb, length); + if (size < 0) { + Q_ASSERT("Error in CE TextCodec"); + return QString(); + } + wchar_t* ws = new wchar_t[size + 2]; + ws[size +1] = 0; + ws[size] = 0; + size = mbstowcs(ws, mb, length); + for (int i=0; i< size; i++) + s.append(QChar(ws[i])); + delete [] ws; +#endif + delete mbcs; + return s; +} + +QByteArray QWindowsLocalCodec::convertFromUnicode(const QChar *ch, int uclen, ConverterState *) const +{ + if (!ch) + return QByteArray(); + if (uclen == 0) + return QByteArray(""); + BOOL used_def; + QByteArray mb(4096, 0); + int len; + while (!(len=WideCharToMultiByte(CP_ACP, 0, (const wchar_t*)ch, uclen, + mb.data(), mb.size()-1, 0, &used_def))) + { + int r = GetLastError(); + if (r == ERROR_INSUFFICIENT_BUFFER) { + mb.resize(1+WideCharToMultiByte(CP_ACP, 0, + (const wchar_t*)ch, uclen, + 0, 0, 0, &used_def)); + // and try again... + } else { +#ifndef QT_NO_DEBUG + // Fail. + qWarning("WideCharToMultiByte: Cannot convert multibyte text (error %d): %s (UTF-8)", + r, QString(ch, uclen).toLocal8Bit().data()); +#endif + break; + } + } + mb.resize(len); + return mb; +} + + +QByteArray QWindowsLocalCodec::name() const +{ + return "System"; +} + +int QWindowsLocalCodec::mibEnum() const +{ + return 0; +} + +#else + +/* locale names mostly copied from XFree86 */ +static const char * const iso8859_2locales[] = { + "croatian", "cs", "cs_CS", "cs_CZ","cz", "cz_CZ", "czech", "hr", + "hr_HR", "hu", "hu_HU", "hungarian", "pl", "pl_PL", "polish", "ro", + "ro_RO", "rumanian", "serbocroatian", "sh", "sh_SP", "sh_YU", "sk", + "sk_SK", "sl", "sl_CS", "sl_SI", "slovak", "slovene", "sr_SP", 0 }; + +static const char * const iso8859_3locales[] = { + "eo", 0 }; + +static const char * const iso8859_4locales[] = { + "ee", "ee_EE", 0 }; + +static const char * const iso8859_5locales[] = { + "mk", "mk_MK", "sp", "sp_YU", 0 }; + +static const char * const cp_1251locales[] = { + "be", "be_BY", "bg", "bg_BG", "bulgarian", 0 }; + +static const char * const pt_154locales[] = { + "ba_RU", "ky", "ky_KG", "kk", "kk_KZ", 0 }; + +static const char * const iso8859_6locales[] = { + "ar_AA", "ar_SA", "arabic", 0 }; + +static const char * const iso8859_7locales[] = { + "el", "el_GR", "greek", 0 }; + +static const char * const iso8859_8locales[] = { + "hebrew", "he", "he_IL", "iw", "iw_IL", 0 }; + +static const char * const iso8859_9locales[] = { + "tr", "tr_TR", "turkish", 0 }; + +static const char * const iso8859_13locales[] = { + "lt", "lt_LT", "lv", "lv_LV", 0 }; + +static const char * const iso8859_15locales[] = { + "et", "et_EE", + // Euro countries + "br_FR", "ca_ES", "de", "de_AT", "de_BE", "de_DE", "de_LU", "en_IE", + "es", "es_ES", "eu_ES", "fi", "fi_FI", "finnish", "fr", "fr_FR", + "fr_BE", "fr_LU", "french", "ga_IE", "gl_ES", "it", "it_IT", "oc_FR", + "nl", "nl_BE", "nl_NL", "pt", "pt_PT", "sv_FI", "wa_BE", + 0 }; + +static const char * const koi8_ulocales[] = { + "uk", "uk_UA", "ru_UA", "ukrainian", 0 }; + +static const char * const tis_620locales[] = { + "th", "th_TH", "thai", 0 }; + +// static const char * const tcvnlocales[] = { +// "vi", "vi_VN", 0 }; + +static bool try_locale_list(const char * const locale[], const QByteArray &lang) +{ + int i; + for(i=0; locale[i] && lang != locale[i]; i++) + ; + return locale[i] != 0; +} + +// For the probably_koi8_locales we have to look. the standard says +// these are 8859-5, but almost all Russian users use KOI8-R and +// incorrectly set $LANG to ru_RU. We'll check tolower() to see what +// it thinks ru_RU means. + +// If you read the history, it seems that many Russians blame ISO and +// Perestroika for the confusion. +// +// The real bug is that some programs break if the user specifies +// ru_RU.KOI8-R. + +static const char * const probably_koi8_rlocales[] = { + "ru", "ru_SU", "ru_RU", "russian", 0 }; + +static QTextCodec * ru_RU_hack(const char * i) { + QTextCodec * ru_RU_codec = 0; + +#if !defined(QT_NO_SETLOCALE) + QByteArray origlocale(setlocale(LC_CTYPE, i)); +#else + QByteArray origlocale(i); +#endif + // unicode koi8r latin5 name + // 0x044E 0xC0 0xEE CYRILLIC SMALL LETTER YU + // 0x042E 0xE0 0xCE CYRILLIC CAPITAL LETTER YU + int latin5 = tolower(0xCE); + int koi8r = tolower(0xE0); + if (koi8r == 0xC0 && latin5 != 0xEE) { + ru_RU_codec = QTextCodec::codecForName("KOI8-R"); + } else if (koi8r != 0xC0 && latin5 == 0xEE) { + ru_RU_codec = QTextCodec::codecForName("ISO 8859-5"); + } else { + // something else again... let's assume... *throws dice* + ru_RU_codec = QTextCodec::codecForName("KOI8-R"); + qWarning("QTextCodec: Using KOI8-R, probe failed (%02x %02x %s)", + koi8r, latin5, i); + } +#if !defined(QT_NO_SETLOCALE) + setlocale(LC_CTYPE, origlocale); +#endif + + return ru_RU_codec; +} + +#endif + +#if !defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) +static QTextCodec *checkForCodec(const QByteArray &name) { + QTextCodec *c = QTextCodec::codecForName(name); + if (!c) { + const int index = name.indexOf('@'); + if (index != -1) { + c = QTextCodec::codecForName(name.left(index)); + } + } + return c; +} +#endif + +/* the next two functions are implicitely thread safe, + as they are only called by setup() which uses a mutex. +*/ +static void setupLocaleMapper() +{ +#ifdef Q_OS_SYMBIAN + localeMapper = QSymbianTextCodec::localeMapper; + if (localeMapper) + return; +#endif + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + localeMapper = QTextCodec::codecForName("System"); +#else + +#ifndef QT_NO_ICONV + localeMapper = QTextCodec::codecForName("System"); +#endif + +#if defined (_XOPEN_UNIX) && !defined(Q_OS_QNX) && !defined(Q_OS_OSF) + if (!localeMapper) { + char *charset = nl_langinfo (CODESET); + if (charset) + localeMapper = QTextCodec::codecForName(charset); + } +#endif + + if (!localeMapper) { + // Very poorly defined and followed standards causes lots of + // code to try to get all the cases... This logic is + // duplicated in QIconvCodec, so if you change it here, change + // it there too. + + // Try to determine locale codeset from locale name assigned to + // LC_CTYPE category. + + // First part is getting that locale name. First try setlocale() which + // definitely knows it, but since we cannot fully trust it, get ready + // to fall back to environment variables. +#if !defined(QT_NO_SETLOCALE) + const QByteArray ctype = setlocale(LC_CTYPE, 0); +#else + const QByteArray ctype; +#endif + + // Get the first nonempty value from $LC_ALL, $LC_CTYPE, and $LANG + // environment variables. + QByteArray lang = qgetenv("LC_ALL"); + if (lang.isEmpty() || lang == "C") { + lang = qgetenv("LC_CTYPE"); + } + if (lang.isEmpty() || lang == "C") { + lang = qgetenv("LANG"); + } + + // Now try these in order: + // 1. CODESET from ctype if it contains a .CODESET part (e.g. en_US.ISO8859-15) + // 2. CODESET from lang if it contains a .CODESET part + // 3. ctype (maybe the locale is named "ISO-8859-1" or something) + // 4. locale (ditto) + // 5. check for "@euro" + // 6. guess locale from ctype unless ctype is "C" + // 7. guess locale from lang + + // 1. CODESET from ctype if it contains a .CODESET part (e.g. en_US.ISO8859-15) + int indexOfDot = ctype.indexOf('.'); + if (indexOfDot != -1) + localeMapper = checkForCodec( ctype.mid(indexOfDot + 1) ); + + // 2. CODESET from lang if it contains a .CODESET part + if (!localeMapper) { + indexOfDot = lang.indexOf('.'); + if (indexOfDot != -1) + localeMapper = checkForCodec( lang.mid(indexOfDot + 1) ); + } + + // 3. ctype (maybe the locale is named "ISO-8859-1" or something) + if (!localeMapper && !ctype.isEmpty() && ctype != "C") + localeMapper = checkForCodec(ctype); + + // 4. locale (ditto) + if (!localeMapper && !lang.isEmpty()) + localeMapper = checkForCodec(lang); + + // 5. "@euro" + if ((!localeMapper && ctype.contains("@euro")) || lang.contains("@euro")) + localeMapper = checkForCodec("ISO 8859-15"); + + // 6. guess locale from ctype unless ctype is "C" + // 7. guess locale from lang + const QByteArray &try_by_name = (!ctype.isEmpty() && ctype != "C") ? lang : ctype; + + // Now do the guessing. + if (!lang.isEmpty() && !localeMapper && !try_by_name.isEmpty()) { + if (try_locale_list(iso8859_15locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-15"); + else if (try_locale_list(iso8859_2locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-2"); + else if (try_locale_list(iso8859_3locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-3"); + else if (try_locale_list(iso8859_4locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-4"); + else if (try_locale_list(iso8859_5locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-5"); + else if (try_locale_list(iso8859_6locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-6"); + else if (try_locale_list(iso8859_7locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-7"); + else if (try_locale_list(iso8859_8locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-8-I"); + else if (try_locale_list(iso8859_9locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-9"); + else if (try_locale_list(iso8859_13locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-13"); + else if (try_locale_list(tis_620locales, lang)) + localeMapper = QTextCodec::codecForName("ISO 8859-11"); + else if (try_locale_list(koi8_ulocales, lang)) + localeMapper = QTextCodec::codecForName("KOI8-U"); + else if (try_locale_list(cp_1251locales, lang)) + localeMapper = QTextCodec::codecForName("CP 1251"); + else if (try_locale_list(pt_154locales, lang)) + localeMapper = QTextCodec::codecForName("PT 154"); + else if (try_locale_list(probably_koi8_rlocales, lang)) + localeMapper = ru_RU_hack(lang); + } + + } + + // If everything failed, we default to 8859-1 + // We could perhaps default to 8859-15. + if (!localeMapper) + localeMapper = QTextCodec::codecForName("ISO 8859-1"); +#endif +} + +#ifndef QT_NO_THREAD +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, textCodecsMutex, (QMutex::Recursive)); +#endif + +// textCodecsMutex need to be locked to enter this function +static void setup() +{ + if (all) + return; + +#ifdef Q_OS_SYMBIAN + // If we don't have a trap handler, we're outside of the main() function, + // ie. in global constructors or destructors. Don't create codecs in this + // case as it would lead to crashes because of a missing cleanup stack on Symbian + if (User::TrapHandler() == NULL) + return; +#endif + +#ifdef Q_DEBUG_TEXTCODEC + if (destroying_is_ok) + qWarning("QTextCodec: Creating new codec during codec cleanup"); +#endif + all = new QList; + // create the cleanup object to cleanup all codecs on exit + (void) createQTextCodecCleanup(); + +#ifndef QT_NO_CODECS + (void)new QTsciiCodec; + for (int i = 0; i < 9; ++i) + (void)new QIsciiCodec(i); + + for (int i = 0; i < QSimpleTextCodec::numSimpleCodecs; ++i) + (void)new QSimpleTextCodec(i); + +#ifdef Q_OS_SYMBIAN + localeMapper = QSymbianTextCodec::init(); +#endif + +# if defined(Q_WS_X11) && !defined(QT_BOOTSTRAPPED) + // no font codecs when bootstrapping + (void)new QFontLaoCodec; +# if defined(QT_NO_ICONV) + // no iconv(3) support, must build all codecs into the library + (void)new QFontGb2312Codec; + (void)new QFontGbkCodec; + (void)new QFontGb18030_0Codec; + (void)new QFontJis0208Codec; + (void)new QFontJis0201Codec; + (void)new QFontKsc5601Codec; + (void)new QFontBig5hkscsCodec; + (void)new QFontBig5Codec; +# endif // QT_NO_ICONV && !QT_BOOTSTRAPPED +# endif // Q_WS_X11 + + +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) +# if defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) + // no asian codecs when bootstrapping, sorry + (void)new QGb18030Codec; + (void)new QGbkCodec; + (void)new QGb2312Codec; + (void)new QEucJpCodec; + (void)new QJisCodec; + (void)new QSjisCodec; + (void)new QEucKrCodec; + (void)new QCP949Codec; + (void)new QBig5Codec; + (void)new QBig5hkscsCodec; +# endif // QT_NO_ICONV && !QT_BOOTSTRAPPED +#endif //Q_OS_SYMBIAN +#endif // QT_NO_CODECS + +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + (void) new QWindowsLocalCodec; +#endif // Q_OS_WIN32 + + (void)new QUtf16Codec; + (void)new QUtf16BECodec; + (void)new QUtf16LECodec; + (void)new QUtf32Codec; + (void)new QUtf32BECodec; + (void)new QUtf32LECodec; +#ifndef Q_OS_SYMBIAN + (void)new QLatin15Codec; +#endif + (void)new QLatin1Codec; + (void)new QUtf8Codec; + +#if !defined(Q_OS_SYMBIAN) && !defined(Q_OS_INTEGRITY) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICONV) && !defined(QT_BOOTSTRAPPED) + // QIconvCodec depends on the UTF-16 codec, so it needs to be created last + (void) new QIconvCodec(); +#endif +#endif + + if (!localeMapper) + setupLocaleMapper(); +} + +/*! + \enum QTextCodec::ConversionFlag + + \value DefaultConversion No flag is set. + \value ConvertInvalidToNull If this flag is set, each invalid input + character is output as a null character. + \value IgnoreHeader Ignore any Unicode byte-order mark and don't generate any. + + \omitvalue FreeFunction +*/ + +/*! + \fn QTextCodec::ConverterState::ConverterState(ConversionFlags flags) + + Constructs a ConverterState object initialized with the given \a flags. +*/ + +/*! + Destroys the ConverterState object. +*/ +QTextCodec::ConverterState::~ConverterState() +{ + if (flags & FreeFunction) + (QTextCodecUnalignedPointer::decode(state_data))(this); + else if (d) + qFree(d); +} + +/*! + \class QTextCodec + \brief The QTextCodec class provides conversions between text encodings. + \reentrant + \ingroup i18n + + Qt uses Unicode to store, draw and manipulate strings. In many + situations you may wish to deal with data that uses a different + encoding. For example, most Japanese documents are still stored + in Shift-JIS or ISO 2022-JP, while Russian users often have their + documents in KOI8-R or Windows-1251. + + Qt provides a set of QTextCodec classes to help with converting + non-Unicode formats to and from Unicode. You can also create your + own codec classes. + + The supported encodings are: + + \list + \o Apple Roman + \o \l{Big5 Text Codec}{Big5} + \o \l{Big5-HKSCS Text Codec}{Big5-HKSCS} + \o CP949 + \o \l{EUC-JP Text Codec}{EUC-JP} + \o \l{EUC-KR Text Codec}{EUC-KR} + \o \l{GBK Text Codec}{GB18030-0} + \o IBM 850 + \o IBM 866 + \o IBM 874 + \o \l{ISO 2022-JP (JIS) Text Codec}{ISO 2022-JP} + \o ISO 8859-1 to 10 + \o ISO 8859-13 to 16 + \o Iscii-Bng, Dev, Gjr, Knd, Mlm, Ori, Pnj, Tlg, and Tml + \o JIS X 0201 + \o JIS X 0208 + \o KOI8-R + \o KOI8-U + \o MuleLao-1 + \o ROMAN8 + \o \l{Shift-JIS Text Codec}{Shift-JIS} + \o TIS-620 + \o \l{TSCII Text Codec}{TSCII} + \o UTF-8 + \o UTF-16 + \o UTF-16BE + \o UTF-16LE + \o UTF-32 + \o UTF-32BE + \o UTF-32LE + \o Windows-1250 to 1258 + \o WINSAMI2 + \endlist + + QTextCodecs can be used as follows to convert some locally encoded + string to Unicode. Suppose you have some string encoded in Russian + KOI8-R encoding, and want to convert it to Unicode. The simple way + to do it is like this: + + \snippet doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp 0 + + After this, \c string holds the text converted to Unicode. + Converting a string from Unicode to the local encoding is just as + easy: + + \snippet doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp 1 + + To read or write files in various encodings, use QTextStream and + its \l{QTextStream::setCodec()}{setCodec()} function. See the + \l{tools/codecs}{Codecs} example for an application of QTextCodec + to file I/O. + + Some care must be taken when trying to convert the data in chunks, + for example, when receiving it over a network. In such cases it is + possible that a multi-byte character will be split over two + chunks. At best this might result in the loss of a character and + at worst cause the entire conversion to fail. + + The approach to use in these situations is to create a QTextDecoder + object for the codec and use this QTextDecoder for the whole + decoding process, as shown below: + + \snippet doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp 2 + + The QTextDecoder object maintains state between chunks and therefore + works correctly even if a multi-byte character is split between + chunks. + + \section1 Creating Your Own Codec Class + + Support for new text encodings can be added to Qt by creating + QTextCodec subclasses. + + The pure virtual functions describe the encoder to the system and + the coder is used as required in the different text file formats + supported by QTextStream, and under X11, for the locale-specific + character input and output. + + To add support for another encoding to Qt, make a subclass of + QTextCodec and implement the functions listed in the table below. + + \table + \header \o Function \o Description + + \row \o name() + \o Returns the official name for the encoding. If the + encoding is listed in the + \l{IANA character-sets encoding file}, the name + should be the preferred MIME name for the encoding. + + \row \o aliases() + \o Returns a list of alternative names for the encoding. + QTextCodec provides a default implementation that returns + an empty list. For example, "ISO-8859-1" has "latin1", + "CP819", "IBM819", and "iso-ir-100" as aliases. + + \row \o mibEnum() + \o Return the MIB enum for the encoding if it is listed in + the \l{IANA character-sets encoding file}. + + \row \o convertToUnicode() + \o Converts an 8-bit character string to Unicode. + + \row \o convertFromUnicode() + \o Converts a Unicode string to an 8-bit character string. + \endtable + + You may find it more convenient to make your codec class + available as a plugin; see \l{How to Create Qt Plugins} for + details. + + \sa QTextStream, QTextDecoder, QTextEncoder, {Codecs Example} +*/ + +/*! + Constructs a QTextCodec, and gives it the highest precedence. The + QTextCodec should always be constructed on the heap (i.e. with \c + new). Qt takes ownership and will delete it when the application + terminates. +*/ +QTextCodec::QTextCodec() +{ +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + all->prepend(this); +} + + +/*! + \nonreentrant + + Destroys the QTextCodec. Note that you should not delete codecs + yourself: once created they become Qt's responsibility. +*/ +QTextCodec::~QTextCodec() +{ +#ifdef Q_DEBUG_TEXTCODEC + if (!destroying_is_ok) + qWarning("QTextCodec::~QTextCodec: Called by application"); +#endif + if (all) { +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + all->removeAll(this); + QTextCodecCache *cache = qTextCodecCache(); + if (cache) + cache->clear(); + } +} + +/*! + \fn QTextCodec *QTextCodec::codecForName(const char *name) + + Searches all installed QTextCodec objects and returns the one + which best matches \a name; the match is case-insensitive. Returns + 0 if no codec matching the name \a name could be found. +*/ + +/*! + Searches all installed QTextCodec objects and returns the one + which best matches \a name; the match is case-insensitive. Returns + 0 if no codec matching the name \a name could be found. +*/ +QTextCodec *QTextCodec::codecForName(const QByteArray &name) +{ + if (name.isEmpty()) + return 0; + +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + + if (!validCodecs()) + return 0; + + QTextCodecCache *cache = qTextCodecCache(); + QTextCodec *codec; + if (cache) { + codec = cache->value(name); + if (codec) + return codec; + } + + for (int i = 0; i < all->size(); ++i) { + QTextCodec *cursor = all->at(i); + if (nameMatch(cursor->name(), name)) { + if (cache) + cache->insert(name, cursor); + return cursor; + } + QList aliases = cursor->aliases(); + for (int y = 0; y < aliases.size(); ++y) + if (nameMatch(aliases.at(y), name)) { + if (cache) + cache->insert(name, cursor); + return cursor; + } + } + + codec = createForName(name); + if (codec && cache) + cache->insert(name, codec); + return codec; +} + + +/*! + Returns the QTextCodec which matches the \link + QTextCodec::mibEnum() MIBenum\endlink \a mib. +*/ +QTextCodec* QTextCodec::codecForMib(int mib) +{ +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + + if (!validCodecs()) + return 0; + + QByteArray key = "MIB: " + QByteArray::number(mib); + QTextCodecCache *cache = qTextCodecCache(); + QTextCodec *codec; + if (cache) { + codec = cache->value(key); + if (codec) + return codec; + } + + QList::ConstIterator i; + for (int i = 0; i < all->size(); ++i) { + QTextCodec *cursor = all->at(i); + if (cursor->mibEnum() == mib) { + if (cache) + cache->insert(key, cursor); + return cursor; + } + } + + codec = createForMib(mib); + + // Qt 3 used 1000 (mib for UCS2) as its identifier for the utf16 codec. Map + // this correctly for compatibility. + if (!codec && mib == 1000) + return codecForMib(1015); + + if (codec && cache) + cache->insert(key, codec); + return codec; +} + +/*! + Returns the list of all available codecs, by name. Call + QTextCodec::codecForName() to obtain the QTextCodec for the name. + + The list may contain many mentions of the same codec + if the codec has aliases. + + \sa availableMibs(), name(), aliases() +*/ +QList QTextCodec::availableCodecs() +{ +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + + QList codecs; + + if (!validCodecs()) + return codecs; + + for (int i = 0; i < all->size(); ++i) { + codecs += all->at(i)->name(); + codecs += all->at(i)->aliases(); + } + +#ifndef QT_NO_THREAD + locker.unlock(); +#endif + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) + QFactoryLoader *l = loader(); + QStringList keys = l->keys(); + for (int i = 0; i < keys.size(); ++i) { + if (!keys.at(i).startsWith(QLatin1String("MIB: "))) { + QByteArray name = keys.at(i).toLatin1(); + if (!codecs.contains(name)) + codecs += name; + } + } +#endif + + return codecs; +} + +/*! + Returns the list of MIBs for all available codecs. Call + QTextCodec::codecForMib() to obtain the QTextCodec for the MIB. + + \sa availableCodecs(), mibEnum() +*/ +QList QTextCodec::availableMibs() +{ +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + + QList codecs; + + if (!validCodecs()) + return codecs; + + for (int i = 0; i < all->size(); ++i) + codecs += all->at(i)->mibEnum(); + +#ifndef QT_NO_THREAD + locker.unlock(); +#endif + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_TEXTCODECPLUGIN) + QFactoryLoader *l = loader(); + QStringList keys = l->keys(); + for (int i = 0; i < keys.size(); ++i) { + if (keys.at(i).startsWith(QLatin1String("MIB: "))) { + int mib = keys.at(i).mid(5).toInt(); + if (!codecs.contains(mib)) + codecs += mib; + } + } +#endif + + return codecs; +} + +/*! + Set the codec to \a c; this will be returned by + codecForLocale(). If \a c is a null pointer, the codec is reset to + the default. + + This might be needed for some applications that want to use their + own mechanism for setting the locale. + + \sa codecForLocale() +*/ +void QTextCodec::setCodecForLocale(QTextCodec *c) +{ +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + localeMapper = c; + if (!localeMapper) + setupLocaleMapper(); +} + +/*! + Returns a pointer to the codec most suitable for this locale. + + On Windows, the codec will be based on a system locale. On Unix + systems, starting with Qt 4.2, the codec will be using the \e + iconv library. Note that in both cases the codec's name will be + "System". +*/ + +QTextCodec* QTextCodec::codecForLocale() +{ + if (!validCodecs()) + return 0; + + if (localeMapper) + return localeMapper; + +#ifndef QT_NO_THREAD + QMutexLocker locker(textCodecsMutex()); +#endif + setup(); + + return localeMapper; +} + + +/*! + \fn QByteArray QTextCodec::name() const + + QTextCodec subclasses must reimplement this function. It returns + the name of the encoding supported by the subclass. + + If the codec is registered as a character set in the + \l{IANA character-sets encoding file} this method should + return the preferred mime name for the codec if defined, + otherwise its name. +*/ + +/*! + \fn int QTextCodec::mibEnum() const + + Subclasses of QTextCodec must reimplement this function. It + returns the MIBenum (see \l{IANA character-sets encoding file} + for more information). It is important that each QTextCodec + subclass returns the correct unique value for this function. +*/ + +/*! + Subclasses can return a number of aliases for the codec in question. + + Standard aliases for codecs can be found in the + \l{IANA character-sets encoding file}. +*/ +QList QTextCodec::aliases() const +{ + return QList(); +} + +/*! + \fn QString QTextCodec::convertToUnicode(const char *chars, int len, + ConverterState *state) const + + QTextCodec subclasses must reimplement this function. + + Converts the first \a len characters of \a chars from the + encoding of the subclass to Unicode, and returns the result in a + QString. + + \a state can be 0, in which case the conversion is stateless and + default conversion rules should be used. If state is not 0, the + codec should save the state after the conversion in \a state, and + adjust the remainingChars and invalidChars members of the struct. +*/ + +/*! + \fn QByteArray QTextCodec::convertFromUnicode(const QChar *input, int number, + ConverterState *state) const + + QTextCodec subclasses must reimplement this function. + + Converts the first \a number of characters from the \a input array + from Unicode to the encoding of the subclass, and returns the result + in a QByteArray. + + \a state can be 0 in which case the conversion is stateless and + default conversion rules should be used. If state is not 0, the + codec should save the state after the conversion in \a state, and + adjust the remainingChars and invalidChars members of the struct. +*/ + +/*! + Creates a QTextDecoder which stores enough state to decode chunks + of \c{char *} data to create chunks of Unicode data. + + The caller is responsible for deleting the returned object. +*/ +QTextDecoder* QTextCodec::makeDecoder() const +{ + return new QTextDecoder(this); +} + +/*! + Creates a QTextDecoder with a specified \a flags to decode chunks + of \c{char *} data to create chunks of Unicode data. + + The caller is responsible for deleting the returned object. + + \since 4.7 +*/ +QTextDecoder* QTextCodec::makeDecoder(QTextCodec::ConversionFlags flags) const +{ + return new QTextDecoder(this, flags); +} + + +/*! + Creates a QTextEncoder which stores enough state to encode chunks + of Unicode data as \c{char *} data. + + The caller is responsible for deleting the returned object. +*/ +QTextEncoder* QTextCodec::makeEncoder() const +{ + return new QTextEncoder(this); +} + +/*! + Creates a QTextEncoder with a specified \a flags to encode chunks + of Unicode data as \c{char *} data. + + The caller is responsible for deleting the returned object. + + \since 4.7 +*/ +QTextEncoder* QTextCodec::makeEncoder(QTextCodec::ConversionFlags flags) const +{ + return new QTextEncoder(this, flags); +} + +/*! + \fn QByteArray QTextCodec::fromUnicode(const QChar *input, int number, + ConverterState *state) const + + Converts the first \a number of characters from the \a input array + from Unicode to the encoding of this codec, and returns the result + in a QByteArray. + + The \a state of the convertor used is updated. +*/ + +/*! + Converts \a str from Unicode to the encoding of this codec, and + returns the result in a QByteArray. +*/ +QByteArray QTextCodec::fromUnicode(const QString& str) const +{ + return convertFromUnicode(str.constData(), str.length(), 0); +} + +/*! + \fn QString QTextCodec::toUnicode(const char *input, int size, + ConverterState *state) const + + Converts the first \a size characters from the \a input from the + encoding of this codec to Unicode, and returns the result in a + QString. + + The \a state of the convertor used is updated. +*/ + +/*! + Converts \a a from the encoding of this codec to Unicode, and + returns the result in a QString. +*/ +QString QTextCodec::toUnicode(const QByteArray& a) const +{ + return convertToUnicode(a.constData(), a.length(), 0); +} + +/*! + Returns true if the Unicode character \a ch can be fully encoded + with this codec; otherwise returns false. +*/ +bool QTextCodec::canEncode(QChar ch) const +{ + ConverterState state; + state.flags = ConvertInvalidToNull; + convertFromUnicode(&ch, 1, &state); + return (state.invalidChars == 0); +} + +/*! + \overload + + \a s contains the string being tested for encode-ability. +*/ +bool QTextCodec::canEncode(const QString& s) const +{ + ConverterState state; + state.flags = ConvertInvalidToNull; + convertFromUnicode(s.constData(), s.length(), &state); + return (state.invalidChars == 0); +} + +#ifdef QT3_SUPPORT +/*! + Returns a string representing the current language and + sublanguage, e.g. "pt" for Portuguese, or "pt_br" for Portuguese/Brazil. + + \sa QLocale +*/ +const char *QTextCodec::locale() +{ + static char locale[6]; + QByteArray l = QLocale::system().name().toLatin1(); + int len = qMin(l.length(), 5); + memcpy(locale, l.constData(), len); + locale[len] = '\0'; + + return locale; +} + +/*! + \overload +*/ + +QByteArray QTextCodec::fromUnicode(const QString& uc, int& lenInOut) const +{ + QByteArray result = convertFromUnicode(uc.constData(), lenInOut, 0); + lenInOut = result.length(); + return result; +} + +/*! + \overload + + \a a contains the source characters; \a len contains the number of + characters in \a a to use. +*/ +QString QTextCodec::toUnicode(const QByteArray& a, int len) const +{ + len = qMin(a.size(), len); + return convertToUnicode(a.constData(), len, 0); +} +#endif + +/*! + \overload + + \a chars contains the source characters. +*/ +QString QTextCodec::toUnicode(const char *chars) const +{ + int len = qstrlen(chars); + return convertToUnicode(chars, len, 0); +} + + +/*! + \class QTextEncoder + \brief The QTextEncoder class provides a state-based encoder. + \reentrant + \ingroup i18n + + A text encoder converts text from Unicode into an encoded text format + using a specific codec. + + The encoder converts Unicode into another format, remembering any + state that is required between calls. + + \sa QTextCodec::makeEncoder(), QTextDecoder +*/ + +/*! + \fn QTextEncoder::QTextEncoder(const QTextCodec *codec) + + Constructs a text encoder for the given \a codec. +*/ + +/*! + Constructs a text encoder for the given \a codec and conversion \a flags. + + \since 4.7 +*/ +QTextEncoder::QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) + : c(codec), state() +{ + state.flags = flags; +} + +/*! + Destroys the encoder. +*/ +QTextEncoder::~QTextEncoder() +{ +} + +/*! \internal + \since 4.5 + Determines whether the eecoder encountered a failure while decoding the input. If + an error was encountered, the produced result is undefined, and gets converted as according + to the conversion flags. + */ +bool QTextEncoder::hasFailure() const +{ + return state.invalidChars != 0; +} + +/*! + Converts the Unicode string \a str into an encoded QByteArray. +*/ +QByteArray QTextEncoder::fromUnicode(const QString& str) +{ + QByteArray result = c->fromUnicode(str.constData(), str.length(), &state); + return result; +} + +/*! + \overload + + Converts \a len characters (not bytes) from \a uc, and returns the + result in a QByteArray. +*/ +QByteArray QTextEncoder::fromUnicode(const QChar *uc, int len) +{ + QByteArray result = c->fromUnicode(uc, len, &state); + return result; +} + +#ifdef QT3_SUPPORT +/*! + \overload + + Converts \a lenInOut characters (not bytes) from \a uc, and returns the + result in a QByteArray. The number of characters read is returned in + the \a lenInOut parameter. +*/ +QByteArray QTextEncoder::fromUnicode(const QString& uc, int& lenInOut) +{ + QByteArray result = c->fromUnicode(uc.constData(), lenInOut, &state); + lenInOut = result.length(); + return result; +} +#endif + +/*! + \class QTextDecoder + \brief The QTextDecoder class provides a state-based decoder. + \reentrant + \ingroup i18n + + A text decoder converts text from an encoded text format into Unicode + using a specific codec. + + The decoder converts text in this format into Unicode, remembering any + state that is required between calls. + + \sa QTextCodec::makeDecoder(), QTextEncoder +*/ + +/*! + \fn QTextDecoder::QTextDecoder(const QTextCodec *codec) + + Constructs a text decoder for the given \a codec. +*/ + +/*! + Constructs a text decoder for the given \a codec and conversion \a flags. + + \since 4.7 +*/ + +QTextDecoder::QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags) + : c(codec), state() +{ + state.flags = flags; +} + +/*! + Destroys the decoder. +*/ +QTextDecoder::~QTextDecoder() +{ +} + +/*! + \fn QString QTextDecoder::toUnicode(const char *chars, int len) + + Converts the first \a len bytes in \a chars to Unicode, returning + the result. + + If not all characters are used (e.g. if only part of a multi-byte + encoding is at the end of the characters), the decoder remembers + enough state to continue with the next call to this function. +*/ +QString QTextDecoder::toUnicode(const char *chars, int len) +{ + return c->toUnicode(chars, len, &state); +} + + +/*! \overload + + The converted string is returned in \a target. + */ +void QTextDecoder::toUnicode(QString *target, const char *chars, int len) +{ + Q_ASSERT(target); + switch (c->mibEnum()) { + case 106: // utf8 + static_cast(c)->convertToUnicode(target, chars, len, &state); + break; + case 4: { // latin1 + target->resize(len); + ushort *data = (ushort*)target->data(); + for (int i = len; i >=0; --i) + data[i] = (uchar) chars[i]; + } break; + default: + *target = c->toUnicode(chars, len, &state); + } +} + + +/*! + \overload + + Converts the bytes in the byte array specified by \a ba to Unicode + and returns the result. +*/ +QString QTextDecoder::toUnicode(const QByteArray &ba) +{ + return c->toUnicode(ba.constData(), ba.length(), &state); +} + + +/*! + \fn QTextCodec* QTextCodec::codecForTr() + + Returns the codec used by QObject::tr() on its argument. If this + function returns 0 (the default), tr() assumes Latin-1. + + \sa setCodecForTr() +*/ + +/*! + \fn void QTextCodec::setCodecForTr(QTextCodec *c) + \nonreentrant + + Sets the codec used by QObject::tr() on its argument to \a c. If + \a c is 0 (the default), tr() assumes Latin-1. + + If the literal quoted text in the program is not in the Latin-1 + encoding, this function can be used to set the appropriate + encoding. For example, software developed by Korean programmers + might use eucKR for all the text in the program, in which case the + main() function might look like this: + + \snippet doc/src/snippets/code/src_corelib_codecs_qtextcodec.cpp 3 + + Note that this is not the way to select the encoding that the \e + user has chosen. For example, to convert an application containing + literal English strings to Korean, all that is needed is for the + English strings to be passed through tr() and for translation + files to be loaded. For details of internationalization, see + \l{Internationalization with Qt}. + + \sa codecForTr(), setCodecForCStrings() +*/ + + +/*! + \fn QTextCodec* QTextCodec::codecForCStrings() + + Returns the codec used by QString to convert to and from \c{const + char *} and QByteArrays. If this function returns 0 (the default), + QString assumes Latin-1. + + \sa setCodecForCStrings() +*/ + +/*! + \fn void QTextCodec::setCodecForCStrings(QTextCodec *codec) + \nonreentrant + + Sets the codec used by QString to convert to and from \c{const + char *} and QByteArrays. If the \a codec is 0 (the default), + QString assumes Latin-1. + + \warning Some codecs do not preserve the characters in the ASCII + range (0x00 to 0x7F). For example, the Japanese Shift-JIS + encoding maps the backslash character (0x5A) to the Yen + character. To avoid undesirable side-effects, we recommend + avoiding such codecs with setCodecsForCString(). + + \sa codecForCStrings(), setCodecForTr() +*/ + +/*! + \since 4.4 + + Tries to detect the encoding of the provided snippet of HTML in + the given byte array, \a ba, by checking the BOM (Byte Order Mark) + and the content-type meta header and returns a QTextCodec instance + that is capable of decoding the html to unicode. If the codec + cannot be detected from the content provided, \a defaultCodec is + returned. + + \sa codecForUtfText() +*/ +QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCodec) +{ + // determine charset + int pos; + QTextCodec *c = 0; + + c = QTextCodec::codecForUtfText(ba, c); + if (!c) { + QByteArray header = ba.left(512).toLower(); + if ((pos = header.indexOf("http-equiv=")) != -1) { + if ((pos = header.lastIndexOf("meta ", pos)) != -1) { + pos = header.indexOf("charset=", pos) + int(strlen("charset=")); + if (pos != -1) { + int pos2 = header.indexOf('\"', pos+1); + QByteArray cs = header.mid(pos, pos2-pos); + // qDebug("found charset: %s", cs.data()); + c = QTextCodec::codecForName(cs); + } + } + } + } + if (!c) + c = defaultCodec; + + return c; +} + +/*! + \overload + + Tries to detect the encoding of the provided snippet of HTML in + the given byte array, \a ba, by checking the BOM (Byte Order Mark) + and the content-type meta header and returns a QTextCodec instance + that is capable of decoding the html to unicode. If the codec cannot + be detected, this overload returns a Latin-1 QTextCodec. +*/ +QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba) +{ + return codecForHtml(ba, QTextCodec::codecForMib(/*Latin 1*/ 4)); +} + +/*! + \since 4.6 + + Tries to detect the encoding of the provided snippet \a ba by + using the BOM (Byte Order Mark) and returns a QTextCodec instance + that is capable of decoding the text to unicode. If the codec + cannot be detected from the content provided, \a defaultCodec is + returned. + + \sa codecForHtml() +*/ +QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec) +{ + const int arraySize = ba.size(); + + if (arraySize > 3) { + if ((uchar)ba[0] == 0x00 + && (uchar)ba[1] == 0x00 + && (uchar)ba[2] == 0xFE + && (uchar)ba[3] == 0xFF) + return QTextCodec::codecForMib(1018); // utf-32 be + else if ((uchar)ba[0] == 0xFF + && (uchar)ba[1] == 0xFE + && (uchar)ba[2] == 0x00 + && (uchar)ba[3] == 0x00) + return QTextCodec::codecForMib(1019); // utf-32 le + } + + if (arraySize < 2) + return defaultCodec; + if ((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff) + return QTextCodec::codecForMib(1013); // utf16 be + else if ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe) + return QTextCodec::codecForMib(1014); // utf16 le + + if (arraySize < 3) + return defaultCodec; + if ((uchar)ba[0] == 0xef + && (uchar)ba[1] == 0xbb + && (uchar)ba[2] == 0xbf) + return QTextCodec::codecForMib(106); // utf-8 + + return defaultCodec; +} + +/*! + \overload + + Tries to detect the encoding of the provided snippet \a ba by + using the BOM (Byte Order Mark) and returns a QTextCodec instance + that is capable of decoding the text to unicode. If the codec + cannot be detected, this overload returns a Latin-1 QTextCodec. + + \sa codecForHtml() +*/ +QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba) +{ + return codecForUtfText(ba, QTextCodec::codecForMib(/*Latin 1*/ 4)); +} + + +/*! \internal + \since 4.3 + Determines whether the decoder encountered a failure while decoding the input. If + an error was encountered, the produced result is undefined, and gets converted as according + to the conversion flags. + */ +bool QTextDecoder::hasFailure() const +{ + return state.invalidChars != 0; +} + +/*! + \fn QTextCodec *QTextCodec::codecForContent(const char *str, int size) + + This functionality is no longer provided by Qt. This + compatibility function always returns a null pointer. +*/ + +/*! + \fn QTextCodec *QTextCodec::codecForName(const char *hint, int accuracy) + + Use the codecForName(const QByteArray &) overload instead. +*/ + +/*! + \fn QTextCodec *QTextCodec::codecForIndex(int i) + + Use availableCodecs() or availableMibs() instead and iterate + through the resulting list. +*/ + + +/*! + \fn QByteArray QTextCodec::mimeName() const + + Use name() instead. +*/ + +QT_END_NAMESPACE + +#endif // QT_NO_TEXTCODEC diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h new file mode 100644 index 0000000000..759a59b66a --- /dev/null +++ b/src/corelib/codecs/qtextcodec.h @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTCODEC_H +#define QTEXTCODEC_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_TEXTCODEC + +class QTextCodec; +class QIODevice; + +class QTextDecoder; +class QTextEncoder; + +class Q_CORE_EXPORT QTextCodec +{ + Q_DISABLE_COPY(QTextCodec) +public: + static QTextCodec* codecForName(const QByteArray &name); + static QTextCodec* codecForName(const char *name) { return codecForName(QByteArray(name)); } + static QTextCodec* codecForMib(int mib); + + static QList availableCodecs(); + static QList availableMibs(); + + static QTextCodec* codecForLocale(); + static void setCodecForLocale(QTextCodec *c); + + static QTextCodec* codecForTr(); + static void setCodecForTr(QTextCodec *c); + + static QTextCodec* codecForCStrings(); + static void setCodecForCStrings(QTextCodec *c); + + static QTextCodec *codecForHtml(const QByteArray &ba); + static QTextCodec *codecForHtml(const QByteArray &ba, QTextCodec *defaultCodec); + + static QTextCodec *codecForUtfText(const QByteArray &ba); + static QTextCodec *codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec); + + bool canEncode(QChar) const; + bool canEncode(const QString&) const; + + QString toUnicode(const QByteArray&) const; + QString toUnicode(const char* chars) const; + QByteArray fromUnicode(const QString& uc) const; + enum ConversionFlag { + DefaultConversion, + ConvertInvalidToNull = 0x80000000, + IgnoreHeader = 0x1, + FreeFunction = 0x2 + }; + Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag) + + struct Q_CORE_EXPORT ConverterState { + ConverterState(ConversionFlags f = DefaultConversion) + : flags(f), remainingChars(0), invalidChars(0), d(0) { state_data[0] = state_data[1] = state_data[2] = 0; } + ~ConverterState(); + ConversionFlags flags; + int remainingChars; + int invalidChars; + uint state_data[3]; + void *d; + private: + Q_DISABLE_COPY(ConverterState) + }; + + QString toUnicode(const char *in, int length, ConverterState *state = 0) const + { return convertToUnicode(in, length, state); } + QByteArray fromUnicode(const QChar *in, int length, ConverterState *state = 0) const + { return convertFromUnicode(in, length, state); } + + // ### Qt 5: merge these functions. + QTextDecoder* makeDecoder() const; + QTextDecoder* makeDecoder(ConversionFlags flags) const; + QTextEncoder* makeEncoder() const; + QTextEncoder* makeEncoder(ConversionFlags flags) const; + + virtual QByteArray name() const = 0; + virtual QList aliases() const; + virtual int mibEnum() const = 0; + +protected: + virtual QString convertToUnicode(const char *in, int length, ConverterState *state) const = 0; + virtual QByteArray convertFromUnicode(const QChar *in, int length, ConverterState *state) const = 0; + + QTextCodec(); + virtual ~QTextCodec(); + +public: +#ifdef QT3_SUPPORT + static QT3_SUPPORT QTextCodec* codecForContent(const char*, int) { return 0; } + static QT3_SUPPORT const char* locale(); + static QT3_SUPPORT QTextCodec* codecForName(const char* hint, int) { return codecForName(QByteArray(hint)); } + QT3_SUPPORT QByteArray fromUnicode(const QString& uc, int& lenInOut) const; + QT3_SUPPORT QString toUnicode(const QByteArray&, int len) const; + QT3_SUPPORT QByteArray mimeName() const { return name(); } + static QT3_SUPPORT QTextCodec *codecForIndex(int i) { return codecForName(availableCodecs().value(i)); } +#endif + +private: + friend class QTextCodecCleanup; + static QTextCodec *cftr; + static bool validCodecs(); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(QTextCodec::ConversionFlags) + + inline QTextCodec* QTextCodec::codecForTr() { return validCodecs() ? cftr : 0; } +inline void QTextCodec::setCodecForTr(QTextCodec *c) { cftr = c; } +inline QTextCodec* QTextCodec::codecForCStrings() { return validCodecs() ? QString::codecForCStrings : 0; } +inline void QTextCodec::setCodecForCStrings(QTextCodec *c) { QString::codecForCStrings = c; } + +class Q_CORE_EXPORT QTextEncoder { + Q_DISABLE_COPY(QTextEncoder) +public: + explicit QTextEncoder(const QTextCodec *codec) : c(codec), state() {} + QTextEncoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); + ~QTextEncoder(); + QByteArray fromUnicode(const QString& str); + QByteArray fromUnicode(const QChar *uc, int len); +#ifdef QT3_SUPPORT + QT3_SUPPORT QByteArray fromUnicode(const QString& uc, int& lenInOut); +#endif + bool hasFailure() const; +private: + const QTextCodec *c; + QTextCodec::ConverterState state; +}; + +class Q_CORE_EXPORT QTextDecoder { + Q_DISABLE_COPY(QTextDecoder) +public: + explicit QTextDecoder(const QTextCodec *codec) : c(codec), state() {} + QTextDecoder(const QTextCodec *codec, QTextCodec::ConversionFlags flags); + ~QTextDecoder(); + QString toUnicode(const char* chars, int len); + QString toUnicode(const QByteArray &ba); + void toUnicode(QString *target, const char *chars, int len); + bool hasFailure() const; +private: + const QTextCodec *c; + QTextCodec::ConverterState state; +}; + +#endif // QT_NO_TEXTCODEC + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTEXTCODEC_H diff --git a/src/corelib/codecs/qtextcodec_p.h b/src/corelib/codecs/qtextcodec_p.h new file mode 100644 index 0000000000..fbf5c1255a --- /dev/null +++ b/src/corelib/codecs/qtextcodec_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTCODEC_P_H +#define QTEXTCODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QTextCodec class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtextcodec.h" +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_TEXTCODEC + +typedef void (*QTextCodecStateFreeFunction)(QTextCodec::ConverterState*); + +struct QTextCodecUnalignedPointer +{ + static inline QTextCodecStateFreeFunction decode(const uint *src) + { + quintptr data; + memcpy(&data, src, sizeof(data)); + return reinterpret_cast(data); + } + static inline void encode(uint *dst, QTextCodecStateFreeFunction fn) + { + quintptr data = reinterpret_cast(fn); + memcpy(dst, &data, sizeof(data)); + } +}; + +#else + +class QTextCodec +{ +public: + enum ConversionFlag { + DefaultConversion, + ConvertInvalidToNull = 0x80000000, + IgnoreHeader = 0x1, + FreeFunction = 0x2 + }; + Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag) + + struct ConverterState { + ConverterState(ConversionFlags f = DefaultConversion) + : flags(f), remainingChars(0), invalidChars(0), d(0) { state_data[0] = state_data[1] = state_data[2] = 0; } + ~ConverterState() { } + ConversionFlags flags; + int remainingChars; + int invalidChars; + uint state_data[3]; + void *d; + private: + Q_DISABLE_COPY(ConverterState) + }; +}; + +#endif //QT_NO_TEXTCODEC + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/codecs/qtextcodec_symbian.cpp b/src/corelib/codecs/qtextcodec_symbian.cpp new file mode 100644 index 0000000000..9ad8ccae1b --- /dev/null +++ b/src/corelib/codecs/qtextcodec_symbian.cpp @@ -0,0 +1,689 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextcodec_p.h" + +#include +#include +#include + +#include + +struct QSymbianCodecInitData { + uint charsetId; + int mib; + const char *aliases; +}; + +/* This table contains the known Symbian codecs aliases. + It is required because symbian does not provide aliases for codecs. + It is also faster to have a name here than asking the system. + It is ordered by charsetId to allow binary search lookup + */ +static const QSymbianCodecInitData codecsData[] = { + { /*268439485*/ KCharacterSetIdentifierShiftJis, 17, "Shift_JIS\0MS_Kanji\0csShiftJIS\0SJIS\0" }, + { /*268439486*/ KCharacterSetIdentifierGb2312, 57, "GB2312\0csGB2312\0CN-GB\0EUC-CN\0" }, // Note: ConvertCharacterSetIdentifierToMibEnumL returns Mib 0 instaead of 57 + { /*268439487*/ KCharacterSetIdentifierBig5, 2026, "Big5\0csBig5\0Big5-ETen\0CP950\0BIG-FIVE\0CN-BIG5\0" }, + { /*268440246*/ KCharacterSetIdentifierCodePage1252, 2252, "windows-1252\0Code Page 1252\0CP1252\0MS-ANSI\0" }, +// { /*268450576*/ KCharacterSetIdentifierIso88591, 4, "ISO-8859-1\0ISO_8859-1:1987\0iso-ir-100\0ISO_8859-1\0latin1\0l1\0IBM819\0CP819\0csISOLatin1\0ISO-IR-100\0ISO8859-1\0L1\0LATIN1\0CSISOLATIN1\0" }, + { /*268451531*/ KCharacterSetIdentifierGbk, 113, "GBK\0MS936\0windows-936\0CP936\0" }, + { /*268451866*/ KCharacterSetIdentifierGb12345, 0, "GB12345\0" }, + { /*268455110*/ KCharacterSetIdentifierAscii, 3, "US-ASCII\0ANSI_X3.4-1968\0iso-ir-6\0ANSI_X3.4-1986\0ISO_646.irv:1991\0ASCII\0ISO646-US\0us\0IBM367\0cp367\0csASCII\0ISO-IR-6\0ISO_646.IRV:1991\0"}, + { /*268456062*/ KCharacterSetIdentifierIso88592, 5, "ISO-8859-2\0ISO_8859-2:1987\0iso-ir-101\0latin2\0l2\0csISOLatin2\0" }, + { /*268456063*/ KCharacterSetIdentifierIso88594, 7, "ISO-8859-4\0ISO_8859-4:1988\0iso-ir-110\0latin4\0l4\0csISOLatin4\0" }, + { /*268456064*/ KCharacterSetIdentifierIso88595, 8, "ISO-8859-5\0ISO_8859-5:1988\0iso-ir-144\0cyrillic\0csISOLatinCyrillic\0" }, + { /*268456065*/ KCharacterSetIdentifierIso88597, 10, "ISO-8859-7\0ISO_8859-7:1987\0iso-ir-126\0ELOT_928\0ECMA-118\0greek\0greek8\0csISOLatinGreek\0" }, + { /*268456066*/ KCharacterSetIdentifierIso88599, 12, "ISO-8859-9\0ISO_8859-9:1989\0iso-ir-148\0latin5\0l5\0csISOLatin5\0" }, + { /*268456875*/ KCharacterSetIdentifierSms7Bit, 0, "SMS 7-bit\0" }, + { /*268458028*/ KCharacterSetIdentifierUtf7, 103, "UTF-7\0UNICODE-1-1-UTF-7\0CSUNICODE11UTF7\0" }, +// { /*268458029*/ KCharacterSetIdentifierUtf8, 106, "UTF-8\0" }, + { /*268458030*/ KCharacterSetIdentifierImapUtf7, 0, "IMAP UTF-7\0" }, + { /*268458031*/ KCharacterSetIdentifierJavaConformantUtf8, 0, "JAVA UTF-8\0" }, + { /*268458454*/ 268458454, 2250, "Windows-1250\0CP1250\0MS-EE\0" }, + { /*268458455*/ 268458455, 2251, "Windows-1251\0CP1251\0MS-CYRL\0" }, + { /*268458456*/ 268458456, 2253, "Windows-1253\0CP1253\0MS-GREEK\0" }, + { /*268458457*/ 268458457, 2254, "Windows-1254\0CP1254\0MS-TURK\0" }, + { /*268458458*/ 268458458, 2257, "Windows-1257\0CP1257\0WINBALTRIM\0" }, + { /*268460133*/ KCharacterSetIdentifierHz, 2085, "HZ-GB-2312\0HZ\0" }, + { /*268460134*/ KCharacterSetIdentifierJis, 16, "JIS_Encoding\0JIS\0" }, + { /*268460135*/ KCharacterSetIdentifierEucJpPacked, 18, "EUC-JP\0Extended_UNIX_Code_Packed_Format_for_Japanese\0csEUCPkdFmtJapanese\0EUCJP_PACKED\0" }, + { /*268461728*/ KCharacterSetIdentifierIso2022Jp, 39, "ISO-2022-JP\0csISO2022JP\0JIS7\0" }, + { /*268461731*/ KCharacterSetIdentifierIso2022Jp1, 0, "ISO2022JP1\0" }, + { /*268470824*/ KCharacterSetIdentifierIso88593, 6, "ISO-8859-3\0ISO_8859-3:1988\0iso-ir-109\0latin3\0l3\0csISOLatin3\0" }, + { /*268470825*/ KCharacterSetIdentifierIso88596, 9, "ISO-8859-6\0ISO_8859-6:1987\0iso-ir-127\0ECMA-114\0ASMO-708\0arabic\0ISO88596\0csISOLatinArabic\0ARABIC\0" }, + { /*268470826*/ KCharacterSetIdentifierIso88598, 11, "ISO-8859-8\0ISO_8859-8:1988\0iso-ir-138\0hebrew\0csISOLatinHebrew\0" }, + { /*268470827*/ KCharacterSetIdentifierIso885910, 13, "ISO-8859-10\0iso-ir-157\0l6\0ISO_8859-10:1992\0csISOLatin6\0latin6\0" }, + { /*268470828*/ KCharacterSetIdentifierIso885913, 109, "ISO-8859-13\0ISO885913\0ISO-IR-179\0ISO8859-13\0L7\0LATIN7\0CSISOLATIN7\0" }, + { /*268470829*/ KCharacterSetIdentifierIso885914, 110, "ISO-8859-14\0iso-ir-199\0ISO_8859-14:1998\0latin8\0iso-celtic\0l8\0" }, + { /*268470830*/ KCharacterSetIdentifierIso885915, 111, "ISO-8859-15\0latin-9\0ISO-IR-203\0" }, +// { /*270483374*/ KCharacterSetIdentifierUnicodeLittle, 1014, "UTF-16LE\0Little-Endian UNICODE\0" }, +// { /*270483538*/ KCharacterSetIdentifierUnicodeBig, 1013, "UTF-16BE\0Big-Endian UNICODE\0" }, + { /*270501191*/ 270501191, 2255, "Windows-1255\0CP1255\0MS-HEBR\0" }, + { /*270501192*/ 270501192, 2256, "Windows-1256\0CP1256\0MS-ARAB\0" }, + { /*270501193*/ 270501193, 2259, "TIS-620\0ISO-IR-166\0TIS620-0\0TIS620.2529-1\0TIS620.2533-0\0TIS620.2533-1\0" }, + { /*270501194*/ 270501194, 0, "windows-874\0CP874\0IBM874\0" }, + { /*270501325*/ 270501325, 0, "SmsStrict\0" }, + { /*270501521*/ 270501521, 0, "ShiftJisDirectmap\0" }, + { /*270501542*/ 270501542, 0, "EucJpDirectmap\0" }, + /* 270501691 (duplicate) Windows-1252 | windows-1252 |Windows-1252 |Code Page 1252 |CP1252 |MS-ANSI |WINDOWS-1252 |2252 */ + { /*270501729*/ 270501729, 2088, "KOI8-U\0" }, + { /*270501752*/ 270501752, 2084, "KOI8-R\0csKOI8R\0" }, + { /*270529682*/ 270529682, 1000, "ISO-10646-UCS-2\0UCS-2\0CSUNICODE\0" }, + { /*270562232*/ 270562232, 2258, "Windows-1258\0CP1258\0WINDOWS-1258\0" }, + { /*270586888*/ 270586888, 0, "J5\0" }, + { /*271011982*/ 271011982, 0, "ISCII\0" }, + { /*271066541*/ 271066541, 2009, "CP850\0IBM850\0""850\0csPC850Multilingual\0" }, // Note: ConvertCharacterSetIdentifierToMibEnumL returns Mib 0 instead of 2009 + { /*271082493*/ 271082493, 0, "EXTENDED_SMS_7BIT\0" }, + { /*271082494*/ 271082494, 0, "gsm7_turkish_single\0" }, + { /*271082495*/ 271082495, 0, "turkish_locking_gsm7ext\0" }, + { /*271082496*/ 271082496, 0, "turkish_locking_single\0" }, + { /*271082503*/ 271082503, 0, "portuguese_gsm7_single\0" }, + { /*271082504*/ 271082504, 0, "portuguese_locking_gsm7ext\0" }, + { /*271082505*/ 271082505, 0, "portuguese_locking_single\0" }, + { /*271082506*/ 271082506, 0, "spanish_gsm7_single\0" }, + { /*271085624*/ 271085624, 114, "GB18030\0" }, + { /*536929574*/ 536929574, 38, "EUC-KR\0" }, + { /*536936703*/ 536936703, 0, "CP949\0" }, + { /*536936705*/ 536936705, 37, "ISO-2022-KR\0csISO2022KR\0" }, + { /*536941517*/ 536941517, 36, "KS_C_5601-1987\0iso-ir-149\0KS_C_5601-1989\0KSC_5601\0Korean\0csKSC56011987\0" } + }; + + +class QSymbianTextCodec : public QTextCodec +{ +public: + QString convertToUnicode(const char*, int, ConverterState*) const; + QByteArray convertFromUnicode(const QChar*, int, ConverterState*) const; + QList aliases() const; + QByteArray name() const; + int mibEnum() const; + + explicit QSymbianTextCodec(uint charsetId, int staticIndex = -1) : m_charsetId(charsetId), m_staticIndex(staticIndex) { } + + static QSymbianTextCodec *init(); + static QSymbianTextCodec *localeMapper; +private: + static CCnvCharacterSetConverter *converter(); + static uint getLanguageDependentCharacterSet(); + uint m_charsetId; + int m_staticIndex; +}; + +QSymbianTextCodec *QSymbianTextCodec::localeMapper = 0; + +class QSymbianTextCodecWithName : public QSymbianTextCodec +{ +public: + QSymbianTextCodecWithName(uint charsetId, const QByteArray &name) + : QSymbianTextCodec(charsetId) , m_name(name) { } + QByteArray name() const { return m_name; } + QList aliases() const { return QList(); } +private: + QByteArray m_name; +}; + +Q_GLOBAL_STATIC(QThreadStorage,gs_converterStore); + +CCnvCharacterSetConverter *QSymbianTextCodec::converter() +{ + CCnvCharacterSetConverter *&conv = gs_converterStore()->localData(); + if (!conv) + QT_TRAP_THROWING(conv = CCnvCharacterSetConverter::NewL()) + return conv; +} + + +QByteArray QSymbianTextCodec::name() const +{ + if (m_staticIndex >= 0) + return QByteArray(codecsData[m_staticIndex].aliases); + QScopedPointer buf; + QT_TRAP_THROWING(buf.reset(converter()->ConvertCharacterSetIdentifierToStandardNameL(m_charsetId, qt_s60GetRFs()))) + if (buf) + return QByteArray(reinterpret_cast(buf->Ptr()), buf->Length()); + return QByteArray(); +} + +int QSymbianTextCodec::mibEnum() const +{ + if (m_staticIndex >= 0) + return codecsData[m_staticIndex].mib; + int mib; + QT_TRAP_THROWING(mib = converter()->ConvertCharacterSetIdentifierToMibEnumL(m_charsetId, qt_s60GetRFs())) + return mib; +} + +QList QSymbianTextCodec::aliases() const +{ + QList result; + if (m_staticIndex >= 0) { + const char *aliases = codecsData[m_staticIndex].aliases; + aliases += strlen(aliases) + 1; + while (*aliases) { + int len = strlen(aliases); + result += QByteArray(aliases, len); + aliases += len + 1; + } + } + return result; +} + + +QString QSymbianTextCodec::convertToUnicode(const char *str, int len, ConverterState *state) const +{ + uint charsetId = m_charsetId; + + // no support for utf7 with state + if (state && (charsetId == KCharacterSetIdentifierUtf7 || + charsetId == KCharacterSetIdentifierImapUtf7)) { + return QString(); + } + CCnvCharacterSetConverter *converter = QSymbianTextCodec::converter(); + if (!str) { + return QString(); + } + + //Search the character set array containing all of the character sets for which conversion is available + CCnvCharacterSetConverter::TAvailability av; + QT_TRAP_THROWING(av = converter->PrepareToConvertToOrFromL(charsetId, qt_s60GetRFs())) + if (av == CCnvCharacterSetConverter::ENotAvailable) { + return QString(); + } + + char *str2; + int len2; + QByteArray helperBA; + if (state && (state->remainingChars > 0)) { + // we should prepare the input string ourselves + // the real size + len2 = len + state->remainingChars; + helperBA.resize(len2); + str2 = helperBA.data(); + if (state->remainingChars > 3) { // doesn't happen usually + memcpy(str2, state->d, state->remainingChars); + qFree(state->d); + state->d = 0; + } else { + char charTbl[3]; + charTbl[0] = state->state_data[0]; + charTbl[1] = state->state_data[1]; + charTbl[2] = state->state_data[2]; + memcpy(str2, charTbl, state->remainingChars); + } + memcpy(str2+state->remainingChars, str, len); + } + else { + len2 = len; + str2 = const_cast(str); + } + + QString UnicodeText(len2, Qt::Uninitialized); + TPtrC8 remainderOfForeignText; + remainderOfForeignText.Set(reinterpret_cast(str2), len2); + + int numberOfUnconvertibleCharacters = 0; + int indexOfFirstUnconvertibleCharacter; + + // Use null character as replacement, if it is asked + bool convertToNull = (state && (state->flags & QTextCodec::ConvertInvalidToNull)); + if (convertToNull) { + _LIT8(KReplacement, "\x00"); + QT_TRAP_THROWING(converter->SetReplacementForUnconvertibleUnicodeCharactersL(KReplacement)) + } + // use state->invalidChars for keeping symbian state + int sState = CCnvCharacterSetConverter::KStateDefault; + if (state && (state->invalidChars != CCnvCharacterSetConverter::KStateDefault)) { + sState = state->invalidChars; + } + //Convert text encoded in a non-Unicode character set into the Unicode character set (UCS-2). + int remainingChars = -1; + int initial_size=0; + while (1) { + TPtr16 UnicodePtr(reinterpret_cast(UnicodeText.data()+initial_size), UnicodeText.size()); + QT_TRAP_THROWING(remainingChars = converter->ConvertToUnicode(UnicodePtr, + remainderOfForeignText, + sState, + numberOfUnconvertibleCharacters, + indexOfFirstUnconvertibleCharacter)) + + initial_size += UnicodePtr.Length(); + // replace 0xFFFD with 0x0000 and only if state set to convert to it + if (numberOfUnconvertibleCharacters>0 && convertToNull) { + int len2 = UnicodePtr.Length(); + for (int i = indexOfFirstUnconvertibleCharacter; i < len2; i++) { + UnicodePtr[i] = 0x0000; + } + } + // success + if (remainingChars==KErrNone) { + break; + } + // if ConvertToUnicode could not consume the foreign text at all + // UTF-8: EErrorIllFormedInput = KErrCorrupt + // UCS-2: KErrNotFound + if (remainingChars == CCnvCharacterSetConverter::EErrorIllFormedInput || + remainingChars == KErrNotFound) { + remainingChars = remainderOfForeignText.Size(); + break; + } + else { + if (remainingChars < 0) { + return QString(); + } + } + // + UnicodeText.resize(UnicodeText.size() + remainingChars*2); + remainderOfForeignText.Set(reinterpret_cast(str2+len2-remainingChars), remainingChars); + } + // save symbian state + if (state) { + state->invalidChars = sState; + } + + if (remainingChars > 0) { + if (!state) { + // No way to signal, if there is still remaining chars, for ex. UTF-8 still can have + // some characters hanging around. + return QString(); + } + const unsigned char *charPtr = remainderOfForeignText.Right(remainingChars).Ptr(); + if (remainingChars > 3) { // doesn't happen usually + state->d = (void*)qMalloc(remainingChars); + if (!state->d) + return QString(); + // copy characters there + memcpy(state->d, charPtr, remainingChars); + } + else { + // fallthru is correct + switch (remainingChars) { + case 3: + state->state_data[2] = charPtr[2]; + case 2: + state->state_data[1] = charPtr[1]; + case 1: + state->state_data[0] = charPtr[0]; + } + } + state->remainingChars = remainingChars; + } + else { + if (state) { + // If we continued from an earlier iteration + state->remainingChars = 0; + } + } + // check if any ORIGINAL headers should be left + if (initial_size > 0) { + if (!state || (state && !(state->flags & QTextCodec::IgnoreHeader))) { + // always skip headers on following state loops + if (state) { + state->flags |= QTextCodec::IgnoreHeader; + } + const TUint16 *ptr = reinterpret_cast(UnicodeText.data()); + if (ptr[0] == QChar::ByteOrderMark || ptr[0] == QChar::ByteOrderSwapped) { + return UnicodeText.mid(1, initial_size - 1); + } + } + } + if (initial_size >= 0) { + UnicodeText.resize(initial_size); + return UnicodeText; + } + else { + return QString(); + } +} + + +QByteArray QSymbianTextCodec::convertFromUnicode(const QChar *str, int len, ConverterState *state) const +{ + uint charsetId = m_charsetId; + CCnvCharacterSetConverter *converter = QSymbianTextCodec::converter(); + if (!str) + return QByteArray(); + + if (len == 0) + return QByteArray(); + + // no support for utf7 with state + if (state && (charsetId == KCharacterSetIdentifierUtf7 || + charsetId == KCharacterSetIdentifierImapUtf7)) + return QByteArray(); + + //Get reference file session from backend + RFs &fileSession = qt_s60GetRFs(); + + //Search the character set array containing all of the character sets for which conversion is available + CCnvCharacterSetConverter::TAvailability av = CCnvCharacterSetConverter::ENotAvailable; + QT_TRAP_THROWING(av = converter->PrepareToConvertToOrFromL(charsetId, fileSession)) + if (av == CCnvCharacterSetConverter::ENotAvailable) + return QByteArray(); + + // Use null character as replacement, if it is asked + if (state && (state->flags & QTextCodec::ConvertInvalidToNull)) { + _LIT8(KReplacement, "\x00"); + QT_TRAP_THROWING(converter->SetReplacementForUnconvertibleUnicodeCharactersL(KReplacement)) + } + else { + _LIT8(KReplacement, "?"); + QT_TRAP_THROWING(converter->SetReplacementForUnconvertibleUnicodeCharactersL(KReplacement)) + } + QByteArray outputBuffer; + + // add header if no state (one run), or if no ignoreheader (from first state) + int bomofs = 0; + if (!state || (state && !(state->flags & QTextCodec::IgnoreHeader))) { + + QChar bom(QChar::ByteOrderMark); + + if (state) + state->flags |= QTextCodec::IgnoreHeader; // bom handling only on first state + + switch (charsetId) { + case KCharacterSetIdentifierUcs2: + outputBuffer.append(bom.row()); + outputBuffer.append(bom.cell()); + bomofs = 2; + break; + + case KCharacterSetIdentifierUtf8: // we don't add bom for UTF-8 + case KCharacterSetIdentifierJavaConformantUtf8: + /*outputBuffer.append("\xef\xbb\xbf"); + bomofs = 3; + */ + break; + + case KCharacterSetIdentifierUnicodeLittle: + outputBuffer.append(bom.cell()); + outputBuffer.append(bom.row()); + bomofs = 2; + break; + + case KCharacterSetIdentifierUnicodeBig: + outputBuffer.append(bom.row()); + outputBuffer.append(bom.cell()); + bomofs = 2; + break; + + default: + break; + } + } + + // len is 16bit chars, reserve 3 8bit chars for each input char + // jsz - it could be differentiated, to allocate less + outputBuffer.resize(len * 3 + bomofs); + + // loop for too short output buffer + int unconverted; + int numberOfUnconvertibleCharacters = len; + int indexOfFirstUnconvertibleCharacter; + int convertedSize; + int lastUnconverted = 0; + int initial_size=0; + int remainderToConvert = len; + while (1) { + TPtr8 outputPtr(reinterpret_cast(outputBuffer.data() + bomofs + initial_size), outputBuffer.size() - bomofs); + + TPtrC16 UnicodeText(reinterpret_cast(str+len-remainderToConvert), remainderToConvert); + + //Convert text encoded in the Unicode character set (UCS-2) into other character sets + unconverted = -1; + QT_TRAP_THROWING( unconverted = converter->ConvertFromUnicode(outputPtr, + UnicodeText, + numberOfUnconvertibleCharacters, + indexOfFirstUnconvertibleCharacter)) + initial_size += outputPtr.Length(); + if (unconverted < 0) { + return QByteArray(); + } + + + if (unconverted == 0 ) { + convertedSize = initial_size; + break; + } + + // check what means unconverted > 0 + if (indexOfFirstUnconvertibleCharacter<0) { + // 8859-6 and 8859-8 break with certain input (string of \xc0 - \xd9 converted to unicode and back) + if (unconverted == lastUnconverted) { + return QByteArray(); + } + lastUnconverted = unconverted; + } + else { + // were some character not possible to convert + + } + remainderToConvert = unconverted; // len - indexOfFirstUnconvertibleCharacter; + // resize output buffer, use =op for the null check + outputBuffer.resize(outputBuffer.size() + remainderToConvert * 3 + bomofs); + }; + + // shorten output + outputBuffer.resize(convertedSize + bomofs); + + if (state) { + state->invalidChars = numberOfUnconvertibleCharacters; + + // check if any Symbian CONVERTED headers should be removed + if (state->flags & QTextCodec::IgnoreHeader && state->state_data[0] == 0) { + + state->state_data[0] = 0xff; // bom handling only on first state + + if (charsetId == KCharacterSetIdentifierUcs2 && outputBuffer.size() > 1) { + + QChar bom(QChar::ByteOrderMark); + if (outputBuffer.at(0) == bom.row() && outputBuffer.at(1) == bom.cell()) { + outputBuffer.remove(0, 2); + } else if (outputBuffer.at(0) == bom.cell() && outputBuffer.at(1) == bom.row()) { + outputBuffer.remove(0, 2); + } + + } else if ((charsetId == KCharacterSetIdentifierUtf8 || + charsetId == KCharacterSetIdentifierJavaConformantUtf8) && + outputBuffer.size() > 2) { + if (outputBuffer.at(0) == 0xef && outputBuffer.at(1) == 0xbb && outputBuffer.at(2) == 0xbf) { + outputBuffer.remove(0, 3); + } + + } else if (charsetId == KCharacterSetIdentifierUnicodeLittle && + outputBuffer.size() > 1) { + + QChar bom(QChar::ByteOrderMark); + if (outputBuffer.at(0) == bom.row() && outputBuffer.at(1) == bom.cell()) { + outputBuffer.remove(0, 2); + } + + } else if (charsetId == KCharacterSetIdentifierUnicodeBig && + outputBuffer.size() > 1) { + + QChar bom(QChar::ByteOrderSwapped); + if (outputBuffer.at(0) == bom.row() && outputBuffer.at(1) == bom.cell()) { + outputBuffer.remove(0, 2); + } + } + + } + } + + return outputBuffer; +} + + +uint QSymbianTextCodec::getLanguageDependentCharacterSet() +{ + TLanguage lang = User::Language(); + + uint langIndex = 0; + + switch (lang) { + case 14: //ELangTurkish + langIndex = KCharacterSetIdentifierIso88599; break; + case 16: //ELangRussian + langIndex = KCharacterSetIdentifierIso88595; break; + case 17: //ELangHungarian + langIndex = KCharacterSetIdentifierIso88592; break; + case 25: //ELangCzec + case 26: //ELangSlovak + case 27: //ELangPolish + case 28: //ELangSlovenian + langIndex = KCharacterSetIdentifierIso88592; break; + case 29: //ELangTaiwanChinese + case 30: //ELangHongKongChinese + langIndex = KCharacterSetIdentifierBig5; break; + case 31: //ELangPrcChinese + langIndex = KCharacterSetIdentifierGbk; break; + case 32: //ELangJapanese + langIndex = KCharacterSetIdentifierShiftJis; break; + case 33: //ELangThai + langIndex = 270501193 /*KCharacterSetIdentifierTis620*/; break; + case 37: //ELangArabic + langIndex = KCharacterSetIdentifierIso88596; break; + case 40: //ELangBelarussian + case 42: //ELangBulgarian + langIndex = KCharacterSetIdentifierIso88595; break; + case 45: //ELangCroatian + langIndex = KCharacterSetIdentifierIso88592; break; + case 49: //ELangEstonian + langIndex = KCharacterSetIdentifierIso88594; break; + case 54: //ELangGreek + case 55: //ELangCyprusGreek + langIndex = KCharacterSetIdentifierIso88597; break; + case 57: //ELangHebrew + langIndex = KCharacterSetIdentifierIso88598; break; + case 58: //ELangHindi + langIndex = 271011982/*KCharacterSetIdentifierIscii*/; break; + case 67: //ELangLatvian + case 68: //ELangLithuanian + langIndex = KCharacterSetIdentifierIso88594; break; + case 69: //ELangMacedonian + langIndex = KCharacterSetIdentifierIso88595; break; + case 78: //ELangRomanian + langIndex = KCharacterSetIdentifierIso88592; break; + case 79: //ELangSerbian + langIndex = KCharacterSetIdentifierIso88592; break; + case 91: //ELangCyprusTurkish + langIndex = KCharacterSetIdentifierIso88599; break; + case 93: //ELangUkrainian + langIndex = KCharacterSetIdentifierIso88595; break; + case 94: //ELangUrdu + langIndex = KCharacterSetIdentifierIso88596; break; + case 157: //ELangEnglish_Taiwan + case 158: //ELangEnglish_HongKong + langIndex = KCharacterSetIdentifierBig5; break; + case 159: //ELangEnglish_Prc + langIndex = KCharacterSetIdentifierGbk; break; + case 160: + langIndex = KCharacterSetIdentifierShiftJis; break; + case 161: //ELangEnglish_Thailand + langIndex = 270501193/*KCharacterSetIdentifierTis620*/; break; + } + + if (langIndex > 0) { + return langIndex; + } + return KCharacterSetIdentifierCodePage1252; +} + +/* Create the codecs that have aliases and return the locale mapper*/ +QSymbianTextCodec *QSymbianTextCodec::init() +{ + const uint localeMapperId = getLanguageDependentCharacterSet(); + QScopedPointer > array; + QT_TRAP_THROWING(array.reset(CCnvCharacterSetConverter::CreateArrayOfCharacterSetsAvailableL(qt_s60GetRFs()))) + CCnvCharacterSetConverter *converter = QSymbianTextCodec::converter(); + int count = array->Count(); + for (int i = 0; i < count; i++) { + int charsetId = array->At(i).Identifier(); + + // skip builtin Qt codecs + if (charsetId == KCharacterSetIdentifierUtf8 || charsetId == KCharacterSetIdentifierUnicodeLittle + || charsetId == KCharacterSetIdentifierUnicodeLittle || charsetId == KCharacterSetIdentifierUnicodeBig + || charsetId == KCharacterSetIdentifierIso88591 + || charsetId == 270501691 /* skip Windows-1252 duplicate*/) { + continue; + } + + int begin = 0; + int n = sizeof(codecsData) / sizeof(codecsData[0]); + int half; + + while (n > 0) { + half = n >> 1; + int middle = begin + half; + if (codecsData[middle].charsetId < charsetId) { + begin = middle + 1; + n -= half + 1; + } else { + n = half; + } + } + if (codecsData[begin].charsetId == charsetId) { + QSymbianTextCodec *c = new QSymbianTextCodec(charsetId, begin); + if (charsetId == localeMapperId) + localeMapper = c; + } else { + // We did not find the charsetId in our codecsData[], therefore we ask + // the OS for the codec name. We first try to get a "standard name" and fall + // back to array->At(i).Name(), if really needed. array->At(i).Name() is not + // guaranteed to be a correct name for QTextCodec::codecFromName(). + QScopedPointer buf; + QT_TRAP_THROWING(buf.reset(converter->ConvertCharacterSetIdentifierToStandardNameL(charsetId, qt_s60GetRFs()))) + QByteArray name; + if (buf && buf->Length()) { + name = QByteArray(reinterpret_cast(buf->Ptr()), buf->Length()); + } else { + TPtrC charSetName = array->At(i).NameIsFileName() ? TParsePtrC(array->At(i).Name()).Name() : array->At(i).Name(); + int len = charSetName.Length(); + QString str; + str.setUnicode(reinterpret_cast(charSetName.Ptr()), len); + name = str.toLatin1(); + } + if (!name.isEmpty()) + new QSymbianTextCodecWithName(charsetId, name); + } + + } + return localeMapper; +} diff --git a/src/corelib/codecs/qtextcodecplugin.cpp b/src/corelib/codecs/qtextcodecplugin.cpp new file mode 100644 index 0000000000..aac98f4362 --- /dev/null +++ b/src/corelib/codecs/qtextcodecplugin.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextcodecplugin.h" +#include "qstringlist.h" + +#ifndef QT_NO_TEXTCODECPLUGIN + +QT_BEGIN_NAMESPACE + +/*! + \class QTextCodecPlugin + \brief The QTextCodecPlugin class provides an abstract base for custom QTextCodec plugins. + \reentrant + \ingroup plugins + + The text codec plugin is a simple plugin interface that makes it + easy to create custom text codecs that can be loaded dynamically + into applications. + + Writing a text codec plugin is achieved by subclassing this base + class, reimplementing the pure virtual functions names(), + aliases(), createForName(), mibEnums() and createForMib(), and + exporting the class with the Q_EXPORT_PLUGIN2() macro. See \l{How + to Create Qt Plugins} for details. + + See the \l{http://www.iana.org/assignments/character-sets}{IANA + character-sets encoding file} for more information on mime + names and mib enums. +*/ + +/*! + \fn QStringList QTextCodecPlugin::names() const + + Returns the list of MIME names supported by this plugin. + + If a codec has several names, the extra names are returned by aliases(). + + \sa createForName(), aliases() +*/ + +/*! + \fn QList QTextCodecPlugin::aliases() const + + Returns the list of aliases supported by this plugin. +*/ + +/*! + \fn QTextCodec *QTextCodecPlugin::createForName(const QByteArray &name) + + Creates a QTextCodec object for the codec called \a name. The \a name + must come from the list of encodings returned by names(). Encoding + names are case sensitive. + + Example: + + \snippet doc/src/snippets/code/src_corelib_codecs_qtextcodecplugin.cpp 0 + + \sa names() +*/ + + +/*! + \fn QList QTextCodecPlugin::mibEnums() const + + Returns the list of mib enums supported by this plugin. + + \sa createForMib() +*/ + +/*! + \fn QTextCodec *QTextCodecPlugin::createForMib(int mib); + + Creates a QTextCodec object for the mib enum \a mib. + + See \l{http://www.iana.org/assignments/character-sets}{the + IANA character-sets encoding file} for more information. + + \sa mibEnums() +*/ + +/*! + Constructs a text codec plugin with the given \a parent. This is + invoked automatically by the Q_EXPORT_PLUGIN2() macro. +*/ +QTextCodecPlugin::QTextCodecPlugin(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the text codec plugin. + + You never have to call this explicitly. Qt destroys a plugin + automatically when it is no longer used. +*/ +QTextCodecPlugin::~QTextCodecPlugin() +{ +} + +QStringList QTextCodecPlugin::keys() const +{ + QStringList keys; + QList list = names(); + list += aliases(); + for (int i = 0; i < list.size(); ++i) + keys += QString::fromLatin1(list.at(i)); + QList mibs = mibEnums(); + for (int i = 0; i < mibs.count(); ++i) + keys += QLatin1String("MIB: ") + QString::number(mibs.at(i)); + return keys; +} + +QTextCodec *QTextCodecPlugin::create(const QString &name) +{ + if (name.startsWith(QLatin1String("MIB: "))) + return createForMib(name.mid(4).toInt()); + return createForName(name.toLatin1()); +} + +QT_END_NAMESPACE + +#endif // QT_NO_TEXTCODECPLUGIN diff --git a/src/corelib/codecs/qtextcodecplugin.h b/src/corelib/codecs/qtextcodecplugin.h new file mode 100644 index 0000000000..80c1d17344 --- /dev/null +++ b/src/corelib/codecs/qtextcodecplugin.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTCODECPLUGIN_H +#define QTEXTCODECPLUGIN_H + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef QT_NO_TEXTCODECPLUGIN + +class QTextCodec; + +struct Q_CORE_EXPORT QTextCodecFactoryInterface : public QFactoryInterface +{ + virtual QTextCodec *create(const QString &key) = 0; +}; + +#define QTextCodecFactoryInterface_iid "com.trolltech.Qt.QTextCodecFactoryInterface" + +Q_DECLARE_INTERFACE(QTextCodecFactoryInterface, QTextCodecFactoryInterface_iid) + + +class Q_CORE_EXPORT QTextCodecPlugin : public QObject, public QTextCodecFactoryInterface +{ + Q_OBJECT + Q_INTERFACES(QTextCodecFactoryInterface:QFactoryInterface) +public: + explicit QTextCodecPlugin(QObject *parent = 0); + ~QTextCodecPlugin(); + + virtual QList names() const = 0; + virtual QList aliases() const = 0; + virtual QTextCodec *createForName(const QByteArray &name) = 0; + + virtual QList mibEnums() const = 0; + virtual QTextCodec *createForMib(int mib) = 0; + +private: + QStringList keys() const; + QTextCodec *create(const QString &name); +}; + +#endif // QT_NO_TEXTCODECPLUGIN + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QTEXTCODECPLUGIN_H diff --git a/src/corelib/codecs/qtsciicodec.cpp b/src/corelib/codecs/qtsciicodec.cpp new file mode 100644 index 0000000000..2550b07eb5 --- /dev/null +++ b/src/corelib/codecs/qtsciicodec.cpp @@ -0,0 +1,498 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Most of the code here was originally written by Hans Petter Bieker, +// and is included in Qt with the author's permission, and the grateful +// thanks of the Qt team. + +#include "qtsciicodec_p.h" +#include "qlist.h" + +#ifndef QT_NO_CODECS + +QT_BEGIN_NAMESPACE + +static unsigned char qt_UnicodeToTSCII(ushort u1, ushort u2, ushort u3); +static unsigned int qt_TSCIIToUnicode(unsigned int code, uint *s); + +#define IsTSCIIChar(c) (((c) >= 0x80) && ((c) <= 0xfd)) + +/*! \class QTsciiCodec + \reentrant + \internal +*/ + +/*! + Destroys the text codec object. +*/ +QTsciiCodec::~QTsciiCodec() +{ +} + +/*! + Converts the first \a len characters in \a uc from Unicode to this + encoding, and returns the result in a byte array. The \a state contains + some conversion flags, and is used by the codec to maintain state + information. +*/ +QByteArray QTsciiCodec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + char replacement = '?'; + if (state) { + if (state->flags & ConvertInvalidToNull) + replacement = 0; + } + int invalid = 0; + + QByteArray rstr(len, Qt::Uninitialized); + uchar* cursor = (uchar*)rstr.data(); + for (int i = 0; i < len; i++) { + QChar ch = uc[i]; + uchar j; + if (ch.row() == 0x00 && ch.cell() < 0x80) { + // ASCII + j = ch.cell(); + } else if ((j = qt_UnicodeToTSCII(uc[i].unicode(), + uc[i + 1].unicode(), + uc[i + 2].unicode()))) { + // We have to check the combined chars first! + i += 2; + } else if ((j = qt_UnicodeToTSCII(uc[i].unicode(), + uc[i + 1].unicode(), 0))) { + i++; + } else if ((j = qt_UnicodeToTSCII(uc[i].unicode(), 0, 0))) { + } else { + // Error + j = replacement; + ++invalid; + } + *cursor++ = j; + } + rstr.resize(cursor - (const uchar*)rstr.constData()); + + if (state) { + state->invalidChars += invalid; + } + return rstr; +} + +/*! + Converts the first \a len characters in \a chars from this encoding + to Unicode, and returns the result in a QString. The \a state contains + some conversion flags, and is used by the codec to maintain state + information. +*/ +QString QTsciiCodec::convertToUnicode(const char* chars, int len, ConverterState *state) const +{ + QChar replacement = QChar::ReplacementCharacter; + if (state) { + if (state->flags & ConvertInvalidToNull) + replacement = QChar::Null; + } + int invalid = 0; + + QString result; + for (int i = 0; i < len; i++) { + uchar ch = chars[i]; + if (ch < 0x80) { + // ASCII + result += QLatin1Char(ch); + } else if (IsTSCIIChar(ch)) { + // TSCII + uint s[3]; + uint u = qt_TSCIIToUnicode(ch, s); + uint *p = s; + while (u--) { + uint c = *p++; + if (c) + result += QChar(c); + else { + result += replacement; + ++invalid; + } + } + } else { + // Invalid + result += replacement; + ++invalid; + } + } + + if (state) { + state->invalidChars += invalid; + } + return result; +} + +/*! + Returns the official name for the encoding that is handled by the codec. + + \sa QTextCodec::name() +*/ +QByteArray QTsciiCodec::name() const +{ + return "TSCII"; +} + +/*! + Returns the MIB enum for the encoding. + + \sa QTextCodec::mibEnum() +*/ +int QTsciiCodec::mibEnum() const +{ + return 2107; +} + +static const int UnToTsLast = 124; // 125 items -- so the last will be 124 +static const ushort UnToTs [][4] = { + // *Sorted* list of TSCII maping for unicode chars + //FIRST SECOND THIRD TSCII + {0x00A0, 0x0000, 0x0000, 0xA0}, + {0x00A9, 0x0000, 0x0000, 0xA9}, + {0x0B83, 0x0000, 0x0000, 0xB7}, + {0x0B85, 0x0000, 0x0000, 0xAB}, + {0x0B86, 0x0000, 0x0000, 0xAC}, + {0x0B87, 0x0000, 0x0000, 0xAD}, + {0x0B88, 0x0000, 0x0000, 0xAE}, + {0x0B89, 0x0000, 0x0000, 0xAF}, + {0x0B8A, 0x0000, 0x0000, 0xB0}, + {0x0B8E, 0x0000, 0x0000, 0xB1}, + {0x0B8F, 0x0000, 0x0000, 0xB2}, + {0x0B90, 0x0000, 0x0000, 0xB3}, + {0x0B92, 0x0000, 0x0000, 0xB4}, + {0x0B93, 0x0000, 0x0000, 0xB5}, + {0x0B94, 0x0000, 0x0000, 0xB6}, + {0x0B95, 0x0000, 0x0000, 0xB8}, + {0x0B95, 0x0B82, 0x0000, 0xEC}, + {0x0B95, 0x0BC1, 0x0000, 0xCC}, + {0x0B95, 0x0BC2, 0x0000, 0xDC}, + {0x0B99, 0x0000, 0x0000, 0xB9}, + {0x0B99, 0x0B82, 0x0000, 0xED}, + {0x0B99, 0x0BC1, 0x0000, 0x99}, + {0x0B99, 0x0BC2, 0x0000, 0x9B}, + {0x0B9A, 0x0000, 0x0000, 0xBA}, + {0x0B9A, 0x0B82, 0x0000, 0xEE}, + {0x0B9A, 0x0BC1, 0x0000, 0xCD}, + {0x0B9A, 0x0BC2, 0x0000, 0xDD}, + {0x0B9C, 0x0000, 0x0000, 0x83}, + {0x0B9C, 0x0B82, 0x0000, 0x88}, + {0x0B9E, 0x0000, 0x0000, 0xBB}, + {0x0B9E, 0x0B82, 0x0000, 0xEF}, + {0x0B9E, 0x0BC1, 0x0000, 0x9A}, + {0x0B9E, 0x0BC2, 0x0000, 0x9C}, + {0x0B9F, 0x0000, 0x0000, 0xBC}, + {0x0B9F, 0x0B82, 0x0000, 0xF0}, + {0x0B9F, 0x0BBF, 0x0000, 0xCA}, + {0x0B9F, 0x0BC0, 0x0000, 0xCB}, + {0x0B9F, 0x0BC1, 0x0000, 0xCE}, + {0x0B9F, 0x0BC2, 0x0000, 0xDE}, + {0x0BA1, 0x0B82, 0x0000, 0xF2}, + {0x0BA3, 0x0000, 0x0000, 0xBD}, + {0x0BA3, 0x0B82, 0x0000, 0xF1}, + {0x0BA3, 0x0BC1, 0x0000, 0xCF}, + {0x0BA3, 0x0BC2, 0x0000, 0xDF}, + {0x0BA4, 0x0000, 0x0000, 0xBE}, + {0x0BA4, 0x0BC1, 0x0000, 0xD0}, + {0x0BA4, 0x0BC2, 0x0000, 0xE0}, + {0x0BA8, 0x0000, 0x0000, 0xBF}, + {0x0BA8, 0x0B82, 0x0000, 0xF3}, + {0x0BA8, 0x0BC1, 0x0000, 0xD1}, + {0x0BA8, 0x0BC2, 0x0000, 0xE1}, + {0x0BA9, 0x0000, 0x0000, 0xC9}, + {0x0BA9, 0x0B82, 0x0000, 0xFD}, + {0x0BA9, 0x0BC1, 0x0000, 0xDB}, + {0x0BA9, 0x0BC2, 0x0000, 0xEB}, + {0x0BAA, 0x0000, 0x0000, 0xC0}, + {0x0BAA, 0x0B82, 0x0000, 0xF4}, + {0x0BAA, 0x0BC1, 0x0000, 0xD2}, + {0x0BAA, 0x0BC2, 0x0000, 0xE2}, + {0x0BAE, 0x0000, 0x0000, 0xC1}, + {0x0BAE, 0x0B82, 0x0000, 0xF5}, + {0x0BAE, 0x0BC1, 0x0000, 0xD3}, + {0x0BAE, 0x0BC2, 0x0000, 0xE3}, + {0x0BAF, 0x0000, 0x0000, 0xC2}, + {0x0BAF, 0x0B82, 0x0000, 0xF6}, + {0x0BAF, 0x0BC1, 0x0000, 0xD4}, + {0x0BAF, 0x0BC2, 0x0000, 0xE4}, + {0x0BB0, 0x0000, 0x0000, 0xC3}, + {0x0BB0, 0x0B82, 0x0000, 0xF7}, + {0x0BB0, 0x0BC1, 0x0000, 0xD5}, + {0x0BB0, 0x0BC2, 0x0000, 0xE5}, + {0x0BB1, 0x0000, 0x0000, 0xC8}, + {0x0BB1, 0x0B82, 0x0000, 0xFC}, + {0x0BB1, 0x0BC1, 0x0000, 0xDA}, + {0x0BB1, 0x0BC2, 0x0000, 0xEA}, + {0x0BB2, 0x0000, 0x0000, 0xC4}, + {0x0BB2, 0x0B82, 0x0000, 0xF8}, + {0x0BB2, 0x0BC1, 0x0000, 0xD6}, + {0x0BB2, 0x0BC2, 0x0000, 0xE6}, + {0x0BB3, 0x0000, 0x0000, 0xC7}, + {0x0BB3, 0x0B82, 0x0000, 0xFB}, + {0x0BB3, 0x0BC1, 0x0000, 0xD9}, + {0x0BB3, 0x0BC2, 0x0000, 0xE9}, + {0x0BB4, 0x0000, 0x0000, 0xC6}, + {0x0BB4, 0x0B82, 0x0000, 0xFA}, + {0x0BB4, 0x0BC1, 0x0000, 0xD8}, + {0x0BB4, 0x0BC2, 0x0000, 0xE8}, + {0x0BB5, 0x0000, 0x0000, 0xC5}, + {0x0BB5, 0x0B82, 0x0000, 0xF9}, + {0x0BB5, 0x0BC1, 0x0000, 0xD7}, + {0x0BB5, 0x0BC2, 0x0000, 0xE7}, + {0x0BB7, 0x0000, 0x0000, 0x84}, + {0x0BB7, 0x0B82, 0x0000, 0x89}, + {0x0BB8, 0x0000, 0x0000, 0x85}, + {0x0BB8, 0x0B82, 0x0000, 0x8A}, + {0x0BB9, 0x0000, 0x0000, 0x86}, + {0x0BB9, 0x0B82, 0x0000, 0x8B}, + {0x0BBE, 0x0000, 0x0000, 0xA1}, + {0x0BBF, 0x0000, 0x0000, 0xA2}, + {0x0BC0, 0x0000, 0x0000, 0xA3}, + {0x0BC1, 0x0000, 0x0000, 0xA4}, + {0x0BC2, 0x0000, 0x0000, 0xA5}, + {0x0BC6, 0x0000, 0x0000, 0xA6}, + {0x0BC7, 0x0000, 0x0000, 0xA7}, + {0x0BC8, 0x0000, 0x0000, 0xA8}, + {0x0BCC, 0x0000, 0x0000, 0xAA}, + {0x0BE6, 0x0000, 0x0000, 0x80}, + {0x0BE7, 0x0000, 0x0000, 0x81}, + {0x0BE7, 0x0BB7, 0x0000, 0x87}, + {0x0BE7, 0x0BB7, 0x0B82, 0x8C}, + {0x0BE8, 0x0000, 0x0000, 0x8D}, + {0x0BE9, 0x0000, 0x0000, 0x8E}, + {0x0BEA, 0x0000, 0x0000, 0x8F}, + {0x0BEB, 0x0000, 0x0000, 0x90}, + {0x0BEC, 0x0000, 0x0000, 0x95}, + {0x0BED, 0x0000, 0x0000, 0x96}, + {0x0BEE, 0x0000, 0x0000, 0x97}, + {0x0BEF, 0x0000, 0x0000, 0x98}, + {0x0BF0, 0x0000, 0x0000, 0x9D}, + {0x0BF1, 0x0000, 0x0000, 0x9E}, + {0x0BF2, 0x0000, 0x0000, 0x9F}, + {0x2018, 0x0000, 0x0000, 0x91}, + {0x2019, 0x0000, 0x0000, 0x92}, + {0x201C, 0x0000, 0x0000, 0x93}, + {0x201C, 0x0000, 0x0000, 0x94} +}; + +static const ushort TsToUn [][3] = { + // Starting at 0x80 + {0x0BE6, 0x0000, 0x0000}, + {0x0BE7, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000}, // unknown + {0x0B9C, 0x0000, 0x0000}, + {0x0BB7, 0x0000, 0x0000}, + {0x0BB8, 0x0000, 0x0000}, + {0x0BB9, 0x0000, 0x0000}, + {0x0BE7, 0x0BB7, 0x0000}, + {0x0B9C, 0x0B82, 0x0000}, + {0x0BB7, 0x0B82, 0x0000}, + {0x0BB8, 0x0B82, 0x0000}, + {0x0BB9, 0x0B82, 0x0000}, + {0x0BE7, 0x0BB7, 0x0B82}, + {0x0BE8, 0x0000, 0x0000}, + {0x0BE9, 0x0000, 0x0000}, + {0x0BEA, 0x0000, 0x0000}, + {0x0BEB, 0x0000, 0x0000}, + {0x2018, 0x0000, 0x0000}, + {0x2019, 0x0000, 0x0000}, + {0x201C, 0x0000, 0x0000}, + {0x201C, 0x0000, 0x0000}, // two of the same?? + {0x0BEC, 0x0000, 0x0000}, + {0x0BED, 0x0000, 0x0000}, + {0x0BEE, 0x0000, 0x0000}, + {0x0BEF, 0x0000, 0x0000}, + {0x0B99, 0x0BC1, 0x0000}, + {0x0B9E, 0x0BC1, 0x0000}, + {0x0B99, 0x0BC2, 0x0000}, + {0x0B9E, 0x0BC2, 0x0000}, + {0x0BF0, 0x0000, 0x0000}, + {0x0BF1, 0x0000, 0x0000}, + {0x0BF2, 0x0000, 0x0000}, + {0x00A0, 0x0000, 0x0000}, + {0x0BBE, 0x0000, 0x0000}, + {0x0BBF, 0x0000, 0x0000}, + {0x0BC0, 0x0000, 0x0000}, + {0x0BC1, 0x0000, 0x0000}, + {0x0BC2, 0x0000, 0x0000}, + {0x0BC6, 0x0000, 0x0000}, + {0x0BC7, 0x0000, 0x0000}, + {0x0BC8, 0x0000, 0x0000}, + {0x00A9, 0x0000, 0x0000}, + {0x0BCC, 0x0000, 0x0000}, + {0x0B85, 0x0000, 0x0000}, + {0x0B86, 0x0000, 0x0000}, + {0x0B87, 0x0000, 0x0000}, + {0x0B88, 0x0000, 0x0000}, + {0x0B89, 0x0000, 0x0000}, + {0x0B8A, 0x0000, 0x0000}, + {0x0B8E, 0x0000, 0x0000}, + {0x0B8F, 0x0000, 0x0000}, + {0x0B90, 0x0000, 0x0000}, + {0x0B92, 0x0000, 0x0000}, + {0x0B93, 0x0000, 0x0000}, + {0x0B94, 0x0000, 0x0000}, + {0x0B83, 0x0000, 0x0000}, + {0x0B95, 0x0000, 0x0000}, + {0x0B99, 0x0000, 0x0000}, + {0x0B9A, 0x0000, 0x0000}, + {0x0B9E, 0x0000, 0x0000}, + {0x0B9F, 0x0000, 0x0000}, + {0x0BA3, 0x0000, 0x0000}, + {0x0BA4, 0x0000, 0x0000}, + {0x0BA8, 0x0000, 0x0000}, + {0x0BAA, 0x0000, 0x0000}, + {0x0BAE, 0x0000, 0x0000}, + {0x0BAF, 0x0000, 0x0000}, + {0x0BB0, 0x0000, 0x0000}, + {0x0BB2, 0x0000, 0x0000}, + {0x0BB5, 0x0000, 0x0000}, + {0x0BB4, 0x0000, 0x0000}, + {0x0BB3, 0x0000, 0x0000}, + {0x0BB1, 0x0000, 0x0000}, + {0x0BA9, 0x0000, 0x0000}, + {0x0B9F, 0x0BBF, 0x0000}, + {0x0B9F, 0x0BC0, 0x0000}, + {0x0B95, 0x0BC1, 0x0000}, + {0x0B9A, 0x0BC1, 0x0000}, + {0x0B9F, 0x0BC1, 0x0000}, + {0x0BA3, 0x0BC1, 0x0000}, + {0x0BA4, 0x0BC1, 0x0000}, + {0x0BA8, 0x0BC1, 0x0000}, + {0x0BAA, 0x0BC1, 0x0000}, + {0x0BAE, 0x0BC1, 0x0000}, + {0x0BAF, 0x0BC1, 0x0000}, + {0x0BB0, 0x0BC1, 0x0000}, + {0x0BB2, 0x0BC1, 0x0000}, + {0x0BB5, 0x0BC1, 0x0000}, + {0x0BB4, 0x0BC1, 0x0000}, + {0x0BB3, 0x0BC1, 0x0000}, + {0x0BB1, 0x0BC1, 0x0000}, + {0x0BA9, 0x0BC1, 0x0000}, + {0x0B95, 0x0BC2, 0x0000}, + {0x0B9A, 0x0BC2, 0x0000}, + {0x0B9F, 0x0BC2, 0x0000}, + {0x0BA3, 0x0BC2, 0x0000}, + {0x0BA4, 0x0BC2, 0x0000}, + {0x0BA8, 0x0BC2, 0x0000}, + {0x0BAA, 0x0BC2, 0x0000}, + {0x0BAE, 0x0BC2, 0x0000}, + {0x0BAF, 0x0BC2, 0x0000}, + {0x0BB0, 0x0BC2, 0x0000}, + {0x0BB2, 0x0BC2, 0x0000}, + {0x0BB5, 0x0BC2, 0x0000}, + {0x0BB4, 0x0BC2, 0x0000}, + {0x0BB3, 0x0BC2, 0x0000}, + {0x0BB1, 0x0BC2, 0x0000}, + {0x0BA9, 0x0BC2, 0x0000}, + {0x0B95, 0x0B82, 0x0000}, + {0x0B99, 0x0B82, 0x0000}, + {0x0B9A, 0x0B82, 0x0000}, + {0x0B9E, 0x0B82, 0x0000}, + {0x0B9F, 0x0B82, 0x0000}, + {0x0BA3, 0x0B82, 0x0000}, + {0x0BA1, 0x0B82, 0x0000}, + {0x0BA8, 0x0B82, 0x0000}, + {0x0BAA, 0x0B82, 0x0000}, + {0x0BAE, 0x0B82, 0x0000}, + {0x0BAF, 0x0B82, 0x0000}, + {0x0BB0, 0x0B82, 0x0000}, + {0x0BB2, 0x0B82, 0x0000}, + {0x0BB5, 0x0B82, 0x0000}, + {0x0BB4, 0x0B82, 0x0000}, + {0x0BB3, 0x0B82, 0x0000}, + {0x0BB1, 0x0B82, 0x0000}, + {0x0BA9, 0x0B82, 0x0000} +}; + +static int cmp(const ushort *s1, const ushort *s2, size_t len) +{ + int diff = 0; + + while (len-- && (diff = *s1++ - *s2++) == 0) + ; + + return diff; +} + +static unsigned char qt_UnicodeToTSCII(ushort u1, ushort u2, ushort u3) +{ + ushort s[3]; + s[0] = u1; + s[1] = u2; + s[2] = u3; + + int a = 0; // start pos + int b = UnToTsLast; // end pos + + // do a binary search for the composed unicode in the list + while (a <= b) { + int w = (a + b) / 2; + int j = cmp(UnToTs[w], s, 3); + + if (j == 0) + // found it + return UnToTs[w][3]; + + if (j < 0) + a = w + 1; + else + b = w - 1; + } + + return 0; +} + +static unsigned int qt_TSCIIToUnicode(uint code, uint *s) +{ + int len = 0; + for (int i = 0; i < 3; i++) { + uint u = TsToUn[code & 0x7f][i]; + s[i] = u; + if (s[i]) len = i + 1; + } + + return len; +} + +QT_END_NAMESPACE + +#endif // QT_NO_CODECS diff --git a/src/corelib/codecs/qtsciicodec_p.h b/src/corelib/codecs/qtsciicodec_p.h new file mode 100644 index 0000000000..7e2bed4e64 --- /dev/null +++ b/src/corelib/codecs/qtsciicodec_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Most of the code here was originally written by Hans Petter Bieker, +// and is included in Qt with the author's permission, and the grateful +// thanks of the Qt team. + +/* + * Copyright (C) 2000 Hans Petter Bieker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef QTSCIICODEC_P_H +#define QTSCIICODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_CODECS + +class QTsciiCodec : public QTextCodec { +public: + ~QTsciiCodec(); + + QByteArray name() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; +}; + +#endif // QT_NO_CODECS + +QT_END_NAMESPACE + +#endif // QTSCIICODEC_P_H diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp new file mode 100644 index 0000000000..c44832936d --- /dev/null +++ b/src/corelib/codecs/qutfcodec.cpp @@ -0,0 +1,670 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qutfcodec_p.h" +#include "qlist.h" +#include "qendian.h" +#include "qchar.h" + +QT_BEGIN_NAMESPACE + +enum { Endian = 0, Data = 1 }; + +static inline bool isUnicodeNonCharacter(uint ucs4) +{ + // Unicode has a couple of "non-characters" that one can use internally, + // but are not allowed to be used for text interchange. + // + // Those are the last two entries each Unicode Plane (U+FFFE, U+FFFF, + // U+1FFFE, U+1FFFF, etc.) as well as the entries between U+FDD0 and + // U+FDEF (inclusive) + + return (ucs4 & 0xfffe) == 0xfffe + || (ucs4 - 0xfdd0U) < 16; +} + +QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state) +{ + uchar replacement = '?'; + int rlen = 3*len; + int surrogate_high = -1; + if (state) { + if (state->flags & QTextCodec::ConvertInvalidToNull) + replacement = 0; + if (!(state->flags & QTextCodec::IgnoreHeader)) + rlen += 3; + if (state->remainingChars) + surrogate_high = state->state_data[0]; + } + + QByteArray rstr; + rstr.resize(rlen); + uchar* cursor = (uchar*)rstr.data(); + const QChar *ch = uc; + int invalid = 0; + if (state && !(state->flags & QTextCodec::IgnoreHeader)) { + *cursor++ = 0xef; + *cursor++ = 0xbb; + *cursor++ = 0xbf; + } + + const QChar *end = ch + len; + while (ch < end) { + uint u = ch->unicode(); + if (surrogate_high >= 0) { + if (u >= 0xdc00 && u < 0xe000) { + u = (surrogate_high - 0xd800)*0x400 + (u - 0xdc00) + 0x10000; + surrogate_high = -1; + } else { + // high surrogate without low + *cursor = replacement; + ++ch; + ++invalid; + surrogate_high = -1; + continue; + } + } else if (u >= 0xdc00 && u < 0xe000) { + // low surrogate without high + *cursor = replacement; + ++ch; + ++invalid; + continue; + } else if (u >= 0xd800 && u < 0xdc00) { + surrogate_high = u; + ++ch; + continue; + } + + if (u < 0x80) { + *cursor++ = (uchar)u; + } else { + if (u < 0x0800) { + *cursor++ = 0xc0 | ((uchar) (u >> 6)); + } else { + // is it one of the Unicode non-characters? + if (isUnicodeNonCharacter(u)) { + *cursor++ = replacement; + ++ch; + ++invalid; + continue; + } + + if (u > 0xffff) { + *cursor++ = 0xf0 | ((uchar) (u >> 18)); + *cursor++ = 0x80 | (((uchar) (u >> 12)) & 0x3f); + } else { + *cursor++ = 0xe0 | (((uchar) (u >> 12)) & 0x3f); + } + *cursor++ = 0x80 | (((uchar) (u >> 6)) & 0x3f); + } + *cursor++ = 0x80 | ((uchar) (u&0x3f)); + } + ++ch; + } + + rstr.resize(cursor - (const uchar*)rstr.constData()); + if (state) { + state->invalidChars += invalid; + state->flags |= QTextCodec::IgnoreHeader; + state->remainingChars = 0; + if (surrogate_high >= 0) { + state->remainingChars = 1; + state->state_data[0] = surrogate_high; + } + } + return rstr; +} + +QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state) +{ + bool headerdone = false; + ushort replacement = QChar::ReplacementCharacter; + int need = 0; + int error = -1; + uint uc = 0; + uint min_uc = 0; + if (state) { + if (state->flags & QTextCodec::IgnoreHeader) + headerdone = true; + if (state->flags & QTextCodec::ConvertInvalidToNull) + replacement = QChar::Null; + need = state->remainingChars; + if (need) { + uc = state->state_data[0]; + min_uc = state->state_data[1]; + } + } + if (!headerdone && len > 3 + && (uchar)chars[0] == 0xef && (uchar)chars[1] == 0xbb && (uchar)chars[2] == 0xbf) { + // starts with a byte order mark + chars += 3; + len -= 3; + headerdone = true; + } + + QString result(need + len + 1, Qt::Uninitialized); // worst case + ushort *qch = (ushort *)result.unicode(); + uchar ch; + int invalid = 0; + + for (int i = 0; i < len; ++i) { + ch = chars[i]; + if (need) { + if ((ch&0xc0) == 0x80) { + uc = (uc << 6) | (ch & 0x3f); + --need; + if (!need) { + // utf-8 bom composes into 0xfeff code point + bool nonCharacter; + if (!headerdone && uc == 0xfeff) { + // don't do anything, just skip the BOM + } else if (!(nonCharacter = isUnicodeNonCharacter(uc)) && uc > 0xffff && uc < 0x110000) { + // surrogate pair + Q_ASSERT((qch - (ushort*)result.unicode()) + 2 < result.length()); + *qch++ = QChar::highSurrogate(uc); + *qch++ = QChar::lowSurrogate(uc); + } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || nonCharacter || uc >= 0x110000) { + // error: overlong sequence, UTF16 surrogate or non-character + *qch++ = replacement; + ++invalid; + } else { + *qch++ = uc; + } + headerdone = true; + } + } else { + // error + i = error; + *qch++ = replacement; + ++invalid; + need = 0; + headerdone = true; + } + } else { + if (ch < 128) { + *qch++ = ushort(ch); + headerdone = true; + } else if ((ch & 0xe0) == 0xc0) { + uc = ch & 0x1f; + need = 1; + error = i; + min_uc = 0x80; + headerdone = true; + } else if ((ch & 0xf0) == 0xe0) { + uc = ch & 0x0f; + need = 2; + error = i; + min_uc = 0x800; + } else if ((ch&0xf8) == 0xf0) { + uc = ch & 0x07; + need = 3; + error = i; + min_uc = 0x10000; + headerdone = true; + } else { + // error + *qch++ = replacement; + ++invalid; + headerdone = true; + } + } + } + if (!state && need > 0) { + // unterminated UTF sequence + for (int i = error; i < len; ++i) { + *qch++ = replacement; + ++invalid; + } + } + result.truncate(qch - (ushort *)result.unicode()); + if (state) { + state->invalidChars += invalid; + state->remainingChars = need; + if (headerdone) + state->flags |= QTextCodec::IgnoreHeader; + state->state_data[0] = need ? uc : 0; + state->state_data[1] = need ? min_uc : 0; + } + return result; +} + +QByteArray QUtf16::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) +{ + DataEndianness endian = e; + int length = 2*len; + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { + length += 2; + } + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; + } + + QByteArray d; + d.resize(length); + char *data = d.data(); + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { + QChar bom(QChar::ByteOrderMark); + if (endian == BigEndianness) { + data[0] = bom.row(); + data[1] = bom.cell(); + } else { + data[0] = bom.cell(); + data[1] = bom.row(); + } + data += 2; + } + if (endian == BigEndianness) { + for (int i = 0; i < len; ++i) { + *(data++) = uc[i].row(); + *(data++) = uc[i].cell(); + } + } else { + for (int i = 0; i < len; ++i) { + *(data++) = uc[i].cell(); + *(data++) = uc[i].row(); + } + } + + if (state) { + state->remainingChars = 0; + state->flags |= QTextCodec::IgnoreHeader; + } + return d; +} + +QString QUtf16::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) +{ + DataEndianness endian = e; + bool half = false; + uchar buf = 0; + bool headerdone = false; + if (state) { + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) + endian = (DataEndianness)state->state_data[Endian]; + if (state->remainingChars) { + half = true; + buf = state->state_data[Data]; + } + } + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; + + QString result(len, Qt::Uninitialized); // worst case + QChar *qch = (QChar *)result.unicode(); + while (len--) { + if (half) { + QChar ch; + if (endian == LittleEndianness) { + ch.setRow(*chars++); + ch.setCell(buf); + } else { + ch.setRow(buf); + ch.setCell(*chars++); + } + if (!headerdone) { + headerdone = true; + if (endian == DetectEndianness) { + if (ch == QChar::ByteOrderSwapped) { + endian = LittleEndianness; + } else if (ch == QChar::ByteOrderMark) { + endian = BigEndianness; + } else { + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + endian = BigEndianness; + } else { + endian = LittleEndianness; + ch = QChar((ch.unicode() >> 8) | ((ch.unicode() & 0xff) << 8)); + } + *qch++ = ch; + } + } else if (ch != QChar::ByteOrderMark) { + *qch++ = ch; + } + } else { + *qch++ = ch; + } + half = false; + } else { + buf = *chars++; + half = true; + } + } + result.truncate(qch - result.unicode()); + + if (state) { + if (headerdone) + state->flags |= QTextCodec::IgnoreHeader; + state->state_data[Endian] = endian; + if (half) { + state->remainingChars = 1; + state->state_data[Data] = buf; + } else { + state->remainingChars = 0; + state->state_data[Data] = 0; + } + } + return result; +} + +QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) +{ + DataEndianness endian = e; + int length = 4*len; + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { + length += 4; + } + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; + } + + QByteArray d(length, Qt::Uninitialized); + char *data = d.data(); + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { + if (endian == BigEndianness) { + data[0] = 0; + data[1] = 0; + data[2] = (char)0xfe; + data[3] = (char)0xff; + } else { + data[0] = (char)0xff; + data[1] = (char)0xfe; + data[2] = 0; + data[3] = 0; + } + data += 4; + } + if (endian == BigEndianness) { + for (int i = 0; i < len; ++i) { + uint cp = uc[i].unicode(); + if (uc[i].isHighSurrogate() && i < len - 1) + cp = QChar::surrogateToUcs4(cp, uc[++i].unicode()); + *(data++) = cp >> 24; + *(data++) = (cp >> 16) & 0xff; + *(data++) = (cp >> 8) & 0xff; + *(data++) = cp & 0xff; + } + } else { + for (int i = 0; i < len; ++i) { + uint cp = uc[i].unicode(); + if (uc[i].isHighSurrogate() && i < len - 1) + cp = QChar::surrogateToUcs4(cp, uc[++i].unicode()); + *(data++) = cp & 0xff; + *(data++) = (cp >> 8) & 0xff; + *(data++) = (cp >> 16) & 0xff; + *(data++) = cp >> 24; + } + } + + if (state) { + state->remainingChars = 0; + state->flags |= QTextCodec::IgnoreHeader; + } + return d; +} + +QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) +{ + DataEndianness endian = e; + uchar tuple[4]; + int num = 0; + bool headerdone = false; + if (state) { + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) { + endian = (DataEndianness)state->state_data[Endian]; + } + num = state->remainingChars; + memcpy(tuple, &state->state_data[Data], 4); + } + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; + + QString result; + result.resize((num + len) >> 2 << 1); // worst case + QChar *qch = (QChar *)result.unicode(); + + const char *end = chars + len; + while (chars < end) { + tuple[num++] = *chars++; + if (num == 4) { + if (!headerdone) { + if (endian == DetectEndianness) { + if (endian == DetectEndianness) { + if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) { + endian = LittleEndianness; + num = 0; + continue; + } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LittleEndianness) { + endian = BigEndianness; + num = 0; + continue; + } else if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + endian = BigEndianness; + } else { + endian = LittleEndianness; + } + } + } else if (((endian == BigEndianness) ? qFromBigEndian(tuple) : qFromLittleEndian(tuple)) == QChar::ByteOrderMark) { + num = 0; + continue; + } + } + uint code = (endian == BigEndianness) ? qFromBigEndian(tuple) : qFromLittleEndian(tuple); + if (code >= 0x10000) { + *qch++ = QChar::highSurrogate(code); + *qch++ = QChar::lowSurrogate(code); + } else { + *qch++ = code; + } + num = 0; + } + } + result.truncate(qch - result.unicode()); + + if (state) { + if (headerdone) + state->flags |= QTextCodec::IgnoreHeader; + state->state_data[Endian] = endian; + state->remainingChars = num; + memcpy(&state->state_data[Data], tuple, 4); + } + return result; +} + + +#ifndef QT_NO_TEXTCODEC + +QUtf8Codec::~QUtf8Codec() +{ +} + +QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf8::convertFromUnicode(uc, len, state); +} + +void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const +{ + *target += QUtf8::convertToUnicode(chars, len, state); +} + +QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf8::convertToUnicode(chars, len, state); +} + +QByteArray QUtf8Codec::name() const +{ + return "UTF-8"; +} + +int QUtf8Codec::mibEnum() const +{ + return 106; +} + +QUtf16Codec::~QUtf16Codec() +{ +} + +QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf16::convertFromUnicode(uc, len, state, e); +} + +QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf16::convertToUnicode(chars, len, state, e); +} + +int QUtf16Codec::mibEnum() const +{ + return 1015; +} + +QByteArray QUtf16Codec::name() const +{ + return "UTF-16"; +} + +QList QUtf16Codec::aliases() const +{ + return QList(); +} + +int QUtf16BECodec::mibEnum() const +{ + return 1013; +} + +QByteArray QUtf16BECodec::name() const +{ + return "UTF-16BE"; +} + +QList QUtf16BECodec::aliases() const +{ + QList list; + return list; +} + +int QUtf16LECodec::mibEnum() const +{ + return 1014; +} + +QByteArray QUtf16LECodec::name() const +{ + return "UTF-16LE"; +} + +QList QUtf16LECodec::aliases() const +{ + QList list; + return list; +} + +QUtf32Codec::~QUtf32Codec() +{ +} + +QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf32::convertFromUnicode(uc, len, state, e); +} + +QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf32::convertToUnicode(chars, len, state, e); +} + +int QUtf32Codec::mibEnum() const +{ + return 1017; +} + +QByteArray QUtf32Codec::name() const +{ + return "UTF-32"; +} + +QList QUtf32Codec::aliases() const +{ + QList list; + return list; +} + +int QUtf32BECodec::mibEnum() const +{ + return 1018; +} + +QByteArray QUtf32BECodec::name() const +{ + return "UTF-32BE"; +} + +QList QUtf32BECodec::aliases() const +{ + QList list; + return list; +} + +int QUtf32LECodec::mibEnum() const +{ + return 1019; +} + +QByteArray QUtf32LECodec::name() const +{ + return "UTF-32LE"; +} + +QList QUtf32LECodec::aliases() const +{ + QList list; + return list; +} + +#endif //QT_NO_TEXTCODEC + +QT_END_NAMESPACE diff --git a/src/corelib/codecs/qutfcodec_p.h b/src/corelib/codecs/qutfcodec_p.h new file mode 100644 index 0000000000..89d27909ae --- /dev/null +++ b/src/corelib/codecs/qutfcodec_p.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUTFCODEC_P_H +#define QUTFCODEC_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qtextcodec.h" +#include "private/qtextcodec_p.h" + +QT_BEGIN_NAMESPACE + +enum DataEndianness +{ + DetectEndianness, + BigEndianness, + LittleEndianness +}; + +struct QUtf8 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *); +}; + +struct QUtf16 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + +struct QUtf32 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + +#ifndef QT_NO_TEXTCODEC + +class QUtf8Codec : public QTextCodec { +public: + ~QUtf8Codec(); + + QByteArray name() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + void convertToUnicode(QString *target, const char *, int, ConverterState *) const; +}; + +class QUtf16Codec : public QTextCodec { +protected: +public: + QUtf16Codec() { e = DetectEndianness; } + ~QUtf16Codec(); + + QByteArray name() const; + QList aliases() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + +protected: + DataEndianness e; +}; + +class QUtf16BECodec : public QUtf16Codec { +public: + QUtf16BECodec() : QUtf16Codec() { e = BigEndianness; } + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + +class QUtf16LECodec : public QUtf16Codec { +public: + QUtf16LECodec() : QUtf16Codec() { e = LittleEndianness; } + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + +class QUtf32Codec : public QTextCodec { +public: + QUtf32Codec() { e = DetectEndianness; } + ~QUtf32Codec(); + + QByteArray name() const; + QList aliases() const; + int mibEnum() const; + + QString convertToUnicode(const char *, int, ConverterState *) const; + QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; + +protected: + DataEndianness e; +}; + +class QUtf32BECodec : public QUtf32Codec { +public: + QUtf32BECodec() : QUtf32Codec() { e = BigEndianness; } + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + +class QUtf32LECodec : public QUtf32Codec { +public: + QUtf32LECodec() : QUtf32Codec() { e = LittleEndianness; } + QByteArray name() const; + QList aliases() const; + int mibEnum() const; +}; + + +#endif // QT_NO_TEXTCODEC + +QT_END_NAMESPACE + +#endif // QUTFCODEC_P_H diff --git a/src/corelib/concurrent/concurrent.pri b/src/corelib/concurrent/concurrent.pri new file mode 100644 index 0000000000..940297139c --- /dev/null +++ b/src/corelib/concurrent/concurrent.pri @@ -0,0 +1,42 @@ +SOURCES += \ + concurrent/qfuture.cpp \ + concurrent/qfutureinterface.cpp \ + concurrent/qfuturesynchronizer.cpp \ + concurrent/qfuturewatcher.cpp \ + concurrent/qrunnable.cpp \ + concurrent/qtconcurrentfilter.cpp \ + concurrent/qtconcurrentmap.cpp \ + concurrent/qtconcurrentresultstore.cpp \ + concurrent/qtconcurrentthreadengine.cpp \ + concurrent/qtconcurrentiteratekernel.cpp \ + concurrent/qtconcurrentexception.cpp \ + concurrent/qthreadpool.cpp + +HEADERS += \ + concurrent/qfuture.h \ + concurrent/qfutureinterface.h \ + concurrent/qfuturesynchronizer.h \ + concurrent/qfuturewatcher.h \ + concurrent/qrunnable.h \ + concurrent/qtconcurrentcompilertest.h \ + concurrent/qtconcurrentexception.h \ + concurrent/qtconcurrentfilter.h \ + concurrent/qtconcurrentfilterkernel.h \ + concurrent/qtconcurrentfunctionwrappers.h \ + concurrent/qtconcurrentiteratekernel.h \ + concurrent/qtconcurrentmap.h \ + concurrent/qtconcurrentmapkernel.h \ + concurrent/qtconcurrentmedian.h \ + concurrent/qtconcurrentreducekernel.h \ + concurrent/qtconcurrentresultstore.h \ + concurrent/qtconcurrentrun.h \ + concurrent/qtconcurrentrunbase.h \ + concurrent/qtconcurrentstoredfunctioncall.h \ + concurrent/qtconcurrentthreadengine.h \ + concurrent/qthreadpool.h + +# private headers +HEADERS += \ + concurrent/qfutureinterface_p.h \ + concurrent/qfuturewatcher_p.h \ + concurrent/qthreadpool_p.h diff --git a/src/corelib/concurrent/qfuture.cpp b/src/corelib/concurrent/qfuture.cpp new file mode 100644 index 0000000000..dfae1de16e --- /dev/null +++ b/src/corelib/concurrent/qfuture.cpp @@ -0,0 +1,697 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class QFuture + \threadsafe + \brief The QFuture class represents the result of an asynchronous computation. + \since 4.4 + + \ingroup thread + + To start a computation, use one of the APIs in the + \l {Concurrent Programming}{Qt Concurrent} framework. + + QFuture allows threads to be synchronized against one or more results + which will be ready at a later point in time. The result can be of any type + that has a default constructor and a copy constructor. If a result is not + available at the time of calling the result(), resultAt(), or results() + functions, QFuture will wait until the result becomes available. You can + use the isResultReadyAt() function to determine if a result is ready or + not. For QFuture objects that report more than one result, the + resultCount() function returns the number of continuous results. This + means that it is always safe to iterate through the results from 0 to + resultCount(). + + QFuture provides a \l{Java-style iterators}{Java-style iterator} + (QFutureIterator) and an \l{STL-style iterators}{STL-style iterator} + (QFuture::const_iterator). Using these iterators is another way to access + results in the future. + + QFuture also offers ways to interact with a runnning computation. For + instance, the computation can be canceled with the cancel() function. To + pause the computation, use the setPaused() function or one of the pause(), + resume(), or togglePaused() convenience functions. Be aware that not all + asynchronous computations can be canceled or paused. For example, the + future returned by QtConcurrent::run() cannot be canceled; but the + future returned by QtConcurrent::mappedReduced() can. + + Progress information is provided by the progressValue(), + progressMinimum(), progressMaximum(), and progressText() functions. The + waitForFinished() function causes the calling thread to block and wait for + the computation to finish, ensuring that all results are available. + + The state of the computation represented by a QFuture can be queried using + the isCanceled(), isStarted(), isFinished(), isRunning(), or isPaused() + functions. + + QFuture is a lightweight reference counted class that can be passed by + value. + + QFuture is specialized to not contain any of the result fetching + functions. Any QFuture can be assigned or copied into a QFuture + as well. This is useful if only status or progress information is needed + - not the actual result data. + + To interact with running tasks using signals and slots, use QFutureWatcher. + + \sa QFutureWatcher, {Concurrent Programming}{Qt Concurrent} +*/ + +/*! \fn QFuture::QFuture() + + Constructs an empty future. +*/ + +/*! \fn QFuture::QFuture(const QFuture &other) + + Constructs a copy of \a other. + + \sa operator=() +*/ + +/*! \fn QFuture::QFuture(QFutureInterface *resultHolder) + \internal +*/ + +/*! \fn QFuture::~QFuture() + + Destroys the future. + + Note that this neither waits nor cancels the asynchronous computation. Use + waitForFinished() or QFutureSynchronizer when you need to ensure that the + computation is completed before the future is destroyed. +*/ + +/*! \fn QFuture &QFuture::operator=(const QFuture &other) + + Assigns \a other to this future and returns a reference to this future. +*/ + +/*! \fn bool QFuture::operator==(const QFuture &other) const + + Returns true if \a other is a copy of this future; otherwise returns false. +*/ + +/*! \fn bool QFuture::operator!=(const QFuture &other) const + + Returns true if \a other is \e not a copy of this future; otherwise returns + false. +*/ + +/*! \fn void QFuture::cancel() + + Cancels the asynchronous computation represented by this future. Note that + the cancelation is asynchronous. Use waitForFinished() after calling + cancel() when you need synchronous cancelation. + + Results currently available may still be accessed on a canceled future, + but new results will \e not become available after calling this function. + Any QFutureWatcher object that is watching this future will not deliver + progress and result ready signals on a canceled future. + + Be aware that not all asynchronous computations can be canceled. For + example, the future returned by QtConcurrent::run() cannot be canceled; + but the future returned by QtConcurrent::mappedReduced() can. +*/ + +/*! \fn bool QFuture::isCanceled() const + + Returns true if the asynchronous computation has been canceled with the + cancel() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See cancel() for more details. +*/ + +/*! \fn void QFuture::setPaused(bool paused) + + If \a paused is true, this function pauses the asynchronous computation + represented by the future. If the computation is already paused, this + function does nothing. Any QFutureWatcher object that is watching this + future will stop delivering progress and result ready signals while the + future is paused. Signal delivery will continue once the future is + resumed. + + If \a paused is false, this function resumes the asynchronous computation. + If the computation was not previously paused, this function does nothing. + + Be aware that not all computations can be paused. For example, the future + returned by QtConcurrent::run() cannot be paused; but the future returned + by QtConcurrent::mappedReduced() can. + + \sa pause(), resume(), togglePaused() +*/ + +/*! \fn bool QFuture::isPaused() const + + Returns true if the asynchronous computation has been paused with the + pause() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See setPaused() for more details. + + \sa setPaused(), togglePaused() +*/ + +/*! \fn void QFuture::pause() + + Pauses the asynchronous computation represented by this future. This is a + convenience method that simply calls setPaused(true). + + \sa resume() +*/ + +/*! \fn void QFuture::resume() + + Resumes the asynchronous computation represented by this future. This is a + convenience method that simply calls setPaused(false). + + \sa pause() +*/ + +/*! \fn void QFuture::togglePaused() + + Toggles the paused state of the asynchronous computation. In other words, + if the computation is currently paused, calling this function resumes it; + if the computation is running, it is paused. This is a convenience method + for calling setPaused(!isPaused()). + + \sa setPaused(), pause(), resume() +*/ + +/*! \fn bool QFuture::isStarted() const + + Returns true if the asynchronous computation represented by this future + has been started; otherwise returns false. +*/ + +/*! \fn bool QFuture::isFinished() const + + Returns true if the asynchronous computation represented by this future + has finished; otherwise returns false. +*/ + +/*! \fn bool QFuture::isRunning() const + + Returns true if the asynchronous computation represented by this future is + currently running; otherwise returns false. +*/ + +/*! \fn int QFuture::resultCount() const + + Returns the number of continuous results available in this future. The real + number of results stored might be different from this value, due to gaps + in the result set. It is always safe to iterate through the results from 0 + to resultCount(). + \sa result(), resultAt(), results() +*/ + +/*! \fn int QFuture::progressValue() const + + Returns the current progress value, which is between the progressMinimum() + and progressMaximum(). + + \sa progressMinimum(), progressMaximum() +*/ + +/*! \fn int QFuture::progressMinimum() const + + Returns the minimum progressValue(). + + \sa progressValue(), progressMaximum() +*/ + +/*! \fn int QFuture::progressMaximum() const + + Returns the maximum progressValue(). + + \sa progressValue(), progressMinimum() +*/ + +/*! \fn QString QFuture::progressText() const + + Returns the (optional) textual representation of the progress as reported + by the asynchronous computation. + + Be aware that not all computations provide a textual representation of the + progress, and as such, this function may return an empty string. +*/ + +/*! \fn void QFuture::waitForFinished() + + Waits for the asynchronous computation to finish (including cancel()ed + computations). +*/ + +/*! \fn T QFuture::result() const + + Returns the first result in the future. If the result is not immediately + available, this function will block and wait for the result to become + available. This is a convenience method for calling resultAt(0). + + \sa resultAt(), results() +*/ + +/*! \fn T QFuture::resultAt(int index) const + + Returns the result at \a index in the future. If the result is not + immediately available, this function will block and wait for the result to + become available. + + \sa result(), results(), resultCount() +*/ + +/*! \fn bool QFuture::isResultReadyAt(int index) const + + Returns true if the result at \a index is immediately available; otherwise + returns false. + + \sa resultAt(), resultCount() +*/ + +/*! \fn QFuture::operator T() const + + Returns the first result in the future. If the result is not immediately + available, this function will block and wait for the result to become + available. This is a convenience method for calling result() or + resultAt(0). + + \sa result(), resultAt(), results() +*/ + +/*! \fn QList QFuture::results() const + + Returns all results from the future. If the results are not immediately + available, this function will block and wait for them to become available. + + \sa result(), resultAt(), resultCount() +*/ + +/*! \fn QFuture::const_iterator QFuture::begin() const + + Returns a const \l{STL-style iterator} pointing to the first result in the + future. + + \sa constBegin(), end() +*/ + +/*! \fn QFuture::const_iterator QFuture::end() const + + Returns a const \l{STL-style iterator} pointing to the imaginary result + after the last result in the future. + + \sa begin(), constEnd() +*/ + +/*! \fn QFuture::const_iterator QFuture::constBegin() const + + Returns a const \l{STL-style iterator} pointing to the first result in the + future. + + \sa begin(), constEnd() +*/ + +/*! \fn QFuture::const_iterator QFuture::constEnd() const + + Returns a const \l{STL-style iterator} pointing to the imaginary result + after the last result in the future. + + \sa constBegin(), end() +*/ + +/*! \class QFuture::const_iterator + \reentrant + \since 4.4 + + \brief The QFuture::const_iterator class provides an STL-style const + iterator for QFuture. + + QFuture provides both \l{STL-style iterators} and \l{Java-style iterators}. + The STL-style iterators are more low-level and more cumbersome to use; on + the other hand, they are slightly faster and, for developers who already + know STL, have the advantage of familiarity. + + The default QFuture::const_iterator constructor creates an uninitialized + iterator. You must initialize it using a QFuture function like + QFuture::constBegin() or QFuture::constEnd() before you start iterating. + Here's a typical loop that prints all the results available in a future: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuture.cpp 0 + + \sa QFutureIterator, QFuture +*/ + +/*! \typedef QFuture::const_iterator::iterator_category + + Typedef for std::bidirectional_iterator_tag. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::difference_type + + Typedef for ptrdiff_t. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::value_type + + Typedef for T. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::pointer + + Typedef for const T *. Provided for STL compatibility. +*/ + +/*! \typedef QFuture::const_iterator::reference + + Typedef for const T &. Provided for STL compatibility. +*/ + +/*! \fn QFuture::const_iterator::const_iterator() + + Constructs an uninitialized iterator. + + Functions like operator*() and operator++() should not be called on an + uninitialized iterartor. Use operator=() to assign a value to it before + using it. + + \sa QFuture::constBegin() QFuture::constEnd() +*/ + +/*! \fn QFuture::const_iterator::const_iterator(QFuture const * const future, int index) + \internal +*/ + +/*! \fn QFuture::const_iterator::const_iterator(const const_iterator &other) + + Constructs a copy of \a other. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator=(const const_iterator &other) + + Assigns \a other to this iterator. +*/ + +/*! \fn const T &QFuture::const_iterator::operator*() const + + Returns the current result. +*/ + +/*! \fn const T *QFuture::const_iterator::operator->() const + + Returns a pointer to the current result. +*/ + +/*! \fn bool QFuture::const_iterator::operator!=(const const_iterator &other) const + + Returns true if \a other points to a different result than this iterator; + otherwise returns false. + + \sa operator==() +*/ + +/*! \fn bool QFuture::const_iterator::operator==(const const_iterator &other) const + + Returns true if \a other points to the same result as this iterator; + otherwise returns false. + + \sa operator!=() +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator++() + + The prefix ++ operator (\c{++it}) advances the iterator to the next result + in the future and returns an iterator to the new current result. + + Calling this function on QFuture::constEnd() leads to undefined results. + + \sa operator--() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator++(int) + + \overload + + The postfix ++ operator (\c{it++}) advances the iterator to the next + result in the future and returns an iterator to the previously current + result. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator--() + + The prefix -- operator (\c{--it}) makes the preceding result current and + returns an iterator to the new current result. + + Calling this function on QFuture::constBegin() leads to undefined results. + + \sa operator++() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator--(int) + + \overload + + The postfix -- operator (\c{it--}) makes the preceding result current and + returns an iterator to the previously current result. +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator+=(int j) + + Advances the iterator by \a j results. (If \a j is negative, the iterator + goes backward.) + + \sa operator-=(), operator+() +*/ + +/*! \fn QFuture::const_iterator &QFuture::const_iterator::operator-=(int j) + + Makes the iterator go back by \a j results. (If \a j is negative, the + iterator goes forward.) + + \sa operator+=(), operator-() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator+(int j) const + + Returns an iterator to the results at \a j positions forward from this + iterator. (If \a j is negative, the iterator goes backward.) + + \sa operator-(), operator+=() +*/ + +/*! \fn QFuture::const_iterator QFuture::const_iterator::operator-(int j) const + + Returns an iterator to the result at \a j positions backward from this + iterator. (If \a j is negative, the iterator goes forward.) + + \sa operator+(), operator-=() +*/ + +/*! \typedef QFuture::ConstIterator + + Qt-style synonym for QFuture::const_iterator. +*/ + +/*! + \class QFutureIterator + \reentrant + \since 4.4 + \inmodule QtCore + + \brief The QFutureIterator class provides a Java-style const iterator for + QFuture. + + QFuture has both \l{Java-style iterators} and \l{STL-style iterators}. The + Java-style iterators are more high-level and easier to use than the + STL-style iterators; on the other hand, they are slightly less efficient. + + An alternative to using iterators is to use index positions. Some QFuture + member functions take an index as their first parameter, making it + possible to access results without using iterators. + + QFutureIterator\ allows you to iterate over a QFuture\. Note that + there is no mutable iterator for QFuture (unlike the other Java-style + iterators). + + The QFutureIterator constructor takes a QFuture as its argument. After + construction, the iterator is located at the very beginning of the result + list (i.e. before the first result). Here's how to iterate over all the + results sequentially: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuture.cpp 1 + + The next() function returns the next result (waiting for it to become + available, if necessary) from the future and advances the iterator. Unlike + STL-style iterators, Java-style iterators point \e between results rather + than directly \e at results. The first call to next() advances the iterator + to the position between the first and second result, and returns the first + result; the second call to next() advances the iterator to the position + between the second and third result, and returns the second result; and + so on. + + \img javaiterators1.png + + Here's how to iterate over the elements in reverse order: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuture.cpp 2 + + If you want to find all occurrences of a particular value, use findNext() + or findPrevious() in a loop. + + Multiple iterators can be used on the same future. If the future is + modified while a QFutureIterator is active, the QFutureIterator will + continue iterating over the original future, ignoring the modified copy. + + \sa QFuture::const_iterator, QFuture +*/ + +/*! + \fn QFutureIterator::QFutureIterator(const QFuture &future) + + Constructs an iterator for traversing \a future. The iterator is set to be + at the front of the result list (before the first result). + + \sa operator=() +*/ + +/*! \fn QFutureIterator &QFutureIterator::operator=(const QFuture &future) + + Makes the iterator operate on \a future. The iterator is set to be at the + front of the result list (before the first result). + + \sa toFront(), toBack() +*/ + +/*! \fn void QFutureIterator::toFront() + + Moves the iterator to the front of the result list (before the first + result). + + \sa toBack(), next() +*/ + +/*! \fn void QFutureIterator::toBack() + + Moves the iterator to the back of the result list (after the last result). + + \sa toFront(), previous() +*/ + +/*! \fn bool QFutureIterator::hasNext() const + + Returns true if there is at least one result ahead of the iterator, e.g., + the iterator is \e not at the back of the result list; otherwise returns + false. + + \sa hasPrevious(), next() +*/ + +/*! \fn const T &QFutureIterator::next() + + Returns the next result and advances the iterator by one position. + + Calling this function on an iterator located at the back of the result + list leads to undefined results. + + \sa hasNext(), peekNext(), previous() +*/ + +/*! \fn const T &QFutureIterator::peekNext() const + + Returns the next result without moving the iterator. + + Calling this function on an iterator located at the back of the result + list leads to undefined results. + + \sa hasNext(), next(), peekPrevious() +*/ + +/*! \fn bool QFutureIterator::hasPrevious() const + + Returns true if there is at least one result ahead of the iterator, e.g., + the iterator is \e not at the front of the result list; otherwise returns + false. + + \sa hasNext(), previous() +*/ + +/*! \fn const T &QFutureIterator::previous() + + Returns the previous result and moves the iterator back by one position. + + Calling this function on an iterator located at the front of the result + list leads to undefined results. + + \sa hasPrevious(), peekPrevious(), next() +*/ + +/*! \fn const T &QFutureIterator::peekPrevious() const + + Returns the previous result without moving the iterator. + + Calling this function on an iterator located at the front of the result + list leads to undefined results. + + \sa hasPrevious(), previous(), peekNext() +*/ + +/*! \fn bool QFutureIterator::findNext(const T &value) + + Searches for \a value starting from the current iterator position forward. + Returns true if \a value is found; otherwise returns false. + + After the call, if \a value was found, the iterator is positioned just + after the matching result; otherwise, the iterator is positioned at the + back of the result list. + + \sa findPrevious() +*/ + +/*! \fn bool QFutureIterator::findPrevious(const T &value) + + Searches for \a value starting from the current iterator position + backward. Returns true if \a value is found; otherwise returns false. + + After the call, if \a value was found, the iterator is positioned just + before the matching result; otherwise, the iterator is positioned at the + front of the result list. + + \sa findNext() +*/ diff --git a/src/corelib/concurrent/qfuture.h b/src/corelib/concurrent/qfuture.h new file mode 100644 index 0000000000..e8a6e264b3 --- /dev/null +++ b/src/corelib/concurrent/qfuture.h @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTURE_H +#define QFUTURE_H + +#include + +#ifndef QT_NO_QFUTURE + +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template +class QFutureWatcher; +template <> +class QFutureWatcher; + +template +class QFuture +{ +public: + QFuture() + : d(QFutureInterface::canceledResult()) + { } + explicit QFuture(QFutureInterface *p) // internal + : d(*p) + { } + QFuture(const QFuture &other) + : d(other.d) + { } + ~QFuture() + { } + + inline QFuture &operator=(const QFuture &other); + bool operator==(const QFuture &other) const { return (d == other.d); } + bool operator!=(const QFuture &other) const { return (d != other.d); } + + void cancel() { d.cancel(); } + bool isCanceled() const { return d.isCanceled(); } + + void setPaused(bool paused) { d.setPaused(paused); } + bool isPaused() const { return d.isPaused(); } + void pause() { setPaused(true); } + void resume() { setPaused(false); } + void togglePaused() { d.togglePaused(); } + + bool isStarted() const { return d.isStarted(); } + bool isFinished() const { return d.isFinished(); } + bool isRunning() const { return d.isRunning(); } + + int resultCount() const { return d.resultCount(); } + int progressValue() const { return d.progressValue(); } + int progressMinimum() const { return d.progressMinimum(); } + int progressMaximum() const { return d.progressMaximum(); } + QString progressText() const { return d.progressText(); } + void waitForFinished() { d.waitForFinished(); } + + inline T result() const; + inline T resultAt(int index) const; + bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); } + + operator T() const { return result(); } + QList results() const { return d.results(); } + + class const_iterator + { + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef qptrdiff difference_type; + typedef T value_type; + typedef const T *pointer; + typedef const T &reference; + + inline const_iterator() {} + inline const_iterator(QFuture const * const _future, int _index) : future(_future), index(_index) {} + inline const_iterator(const const_iterator &o) : future(o.future), index(o.index) {} + inline const_iterator &operator=(const const_iterator &o) + { future = o.future; index = o.index; return *this; } + inline const T &operator*() const { return future->d.resultReference(index); } + inline const T *operator->() const { return future->d.resultPointer(index); } + + inline bool operator!=(const const_iterator &other) const + { + if (index == -1 && other.index == -1) // comparing end != end? + return false; + if (other.index == -1) + return (future->isRunning() || (index < future->resultCount())); + return (index != other.index); + } + + inline bool operator==(const const_iterator &o) const { return !operator!=(o); } + inline const_iterator &operator++() { ++index; return *this; } + inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; } + inline const_iterator &operator--() { --index; return *this; } + inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; } + inline const_iterator operator+(int j) const { return const_iterator(future, index + j); } + inline const_iterator operator-(int j) const { return const_iterator(future, index - j); } + inline const_iterator &operator+=(int j) { index += j; return *this; } + inline const_iterator &operator-=(int j) { index -= j; return *this; } + private: + QFuture const * future; + int index; + }; + friend class const_iterator; + typedef const_iterator ConstIterator; + + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator constBegin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, -1); } + const_iterator constEnd() const { return const_iterator(this, -1); } + +private: + friend class QFutureWatcher; + +public: // Warning: the d pointer is not documented and is considered private. + mutable QFutureInterface d; +}; + +template +inline QFuture &QFuture::operator=(const QFuture &other) +{ + d = other.d; + return *this; +} + +template +inline T QFuture::result() const +{ + d.waitForResult(0); + return d.resultReference(0); +} + +template +inline T QFuture::resultAt(int index) const +{ + d.waitForResult(index); + return d.resultReference(index); +} + +template +inline QFuture QFutureInterface::future() +{ + return QFuture(this); +} + +Q_DECLARE_SEQUENTIAL_ITERATOR(Future) + +template <> +class QFuture +{ +public: + QFuture() + : d(QFutureInterface::canceledResult()) + { } + explicit QFuture(QFutureInterfaceBase *p) // internal + : d(*p) + { } + QFuture(const QFuture &other) + : d(other.d) + { } + ~QFuture() + { } + + QFuture &operator=(const QFuture &other); + bool operator==(const QFuture &other) const { return (d == other.d); } + bool operator!=(const QFuture &other) const { return (d != other.d); } + +#if !defined(Q_CC_XLC) + template + QFuture(const QFuture &other) + : d(other.d) + { } + + template + QFuture &operator=(const QFuture &other) + { + d = other.d; + return *this; + } +#endif + + void cancel() { d.cancel(); } + bool isCanceled() const { return d.isCanceled(); } + + void setPaused(bool paused) { d.setPaused(paused); } + bool isPaused() const { return d.isPaused(); } + void pause() { setPaused(true); } + void resume() { setPaused(false); } + void togglePaused() { d.togglePaused(); } + + bool isStarted() const { return d.isStarted(); } + bool isFinished() const { return d.isFinished(); } + bool isRunning() const { return d.isRunning(); } + + int resultCount() const { return d.resultCount(); } + int progressValue() const { return d.progressValue(); } + int progressMinimum() const { return d.progressMinimum(); } + int progressMaximum() const { return d.progressMaximum(); } + QString progressText() const { return d.progressText(); } + void waitForFinished() { d.waitForFinished(); } + +private: + friend class QFutureWatcher; + +#ifdef QFUTURE_TEST +public: +#endif + mutable QFutureInterfaceBase d; +}; + +inline QFuture &QFuture::operator=(const QFuture &other) +{ + d = other.d; + return *this; +} + +inline QFuture QFutureInterface::future() +{ + return QFuture(this); +} + +template +QFuture qToVoidFuture(const QFuture &future) +{ + return QFuture(future.d); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTURE_H diff --git a/src/corelib/concurrent/qfutureinterface.cpp b/src/corelib/concurrent/qfutureinterface.cpp new file mode 100644 index 0000000000..c5bd802480 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface.cpp @@ -0,0 +1,565 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// qfutureinterface.h included from qfuture.h +#include "qfuture.h" + +#ifndef QT_NO_QFUTURE + +#include +#include +#include +#include + +#include "qfutureinterface_p.h" + +QT_BEGIN_NAMESPACE + +enum { + MaxProgressEmitsPerSecond = 25 +}; + +QFutureInterfaceBase::QFutureInterfaceBase(State initialState) + : d(new QFutureInterfaceBasePrivate(initialState)) +{ } + +QFutureInterfaceBase::QFutureInterfaceBase(const QFutureInterfaceBase &other) + : d(other.d) +{ + d->refCount.ref(); +} + +QFutureInterfaceBase::~QFutureInterfaceBase() +{ + if (!d->refCount.deref()) + delete d; +} + +void QFutureInterfaceBase::cancel() +{ + QMutexLocker locker(&d->m_mutex); + if (d->state & Canceled) + return; + + d->state = State((d->state & ~Paused) | Canceled); + d->waitCondition.wakeAll(); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); +} + +void QFutureInterfaceBase::setPaused(bool paused) +{ + QMutexLocker locker(&d->m_mutex); + if (paused) { + d->state = State(d->state | Paused); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + } else { + d->state = State(d->state & ~Paused); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); + } +} + +void QFutureInterfaceBase::togglePaused() +{ + QMutexLocker locker(&d->m_mutex); + if (d->state & Paused) { + d->state = State(d->state & ~Paused); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Resumed)); + } else { + d->state = State(d->state | Paused); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + } +} + +void QFutureInterfaceBase::setThrottled(bool enable) +{ + // bail out if we are not changing the state + if ((enable && (d->state & Throttled)) || (!enable && !(d->state & Throttled))) + return; + + // lock and change the state + QMutexLocker lock(&d->m_mutex); + if (enable) { + d->state = State(d->state | Throttled); + } else { + d->state = State(d->state & ~Throttled); + if (!(d->state & Paused)) + d->pausedWaitCondition.wakeAll(); + } +} + + +bool QFutureInterfaceBase::isRunning() const +{ + return queryState(Running); +} + +bool QFutureInterfaceBase::isStarted() const +{ + return queryState(Started); +} + +bool QFutureInterfaceBase::isCanceled() const +{ + return queryState(Canceled); +} + +bool QFutureInterfaceBase::isFinished() const +{ + return queryState(Finished); +} + +bool QFutureInterfaceBase::isPaused() const +{ + return queryState(Paused); +} + +bool QFutureInterfaceBase::isThrottled() const +{ + return queryState(Throttled); +} + +bool QFutureInterfaceBase::isResultReadyAt(int index) const +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_isResultReadyAt(index); +} + +bool QFutureInterfaceBase::waitForNextResult() +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_waitForNextResult(); +} + +void QFutureInterfaceBase::waitForResume() +{ + // return early if possible to avoid taking the mutex lock. + if ((d->state & Paused) == false || (d->state & Canceled)) + return; + + QMutexLocker lock(&d->m_mutex); + if ((d->state & Paused) == false || (d->state & Canceled)) + return; + + // decrease active thread count since this thread will wait. + QThreadPool::globalInstance()->releaseThread(); + + d->pausedWaitCondition.wait(&d->m_mutex); + + QThreadPool::globalInstance()->reserveThread(); +} + +int QFutureInterfaceBase::progressValue() const +{ + return d->m_progressValue; +} + +int QFutureInterfaceBase::progressMinimum() const +{ + return d->m_progressMinimum; +} + +int QFutureInterfaceBase::progressMaximum() const +{ + return d->m_progressMaximum; +} + +int QFutureInterfaceBase::resultCount() const +{ + QMutexLocker lock(&d->m_mutex); + return d->internal_resultCount(); +} + +QString QFutureInterfaceBase::progressText() const +{ + QMutexLocker locker(&d->m_mutex); + return d->m_progressText; +} + +bool QFutureInterfaceBase::isProgressUpdateNeeded() const +{ + QMutexLocker locker(&d->m_mutex); + return !d->progressTime.isValid() || (d->progressTime.elapsed() > (1000 / MaxProgressEmitsPerSecond)); +} + +void QFutureInterfaceBase::reportStarted() +{ + QMutexLocker locker(&d->m_mutex); + if ((d->state & Started) || (d->state & Canceled) || (d->state & Finished)) + return; + + d->setState(State(Started | Running)); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Started)); +} + +void QFutureInterfaceBase::reportCanceled() +{ + cancel(); +} + +#ifndef QT_NO_EXCEPTIONS +void QFutureInterfaceBase::reportException(const QtConcurrent::Exception &exception) +{ + QMutexLocker locker(&d->m_mutex); + if ((d->state & Canceled) || (d->state & Finished)) + return; + + d->m_exceptionStore.setException(exception); + d->state = State(d->state | Canceled); + d->waitCondition.wakeAll(); + d->pausedWaitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); +} +#endif + +void QFutureInterfaceBase::reportFinished() +{ + QMutexLocker locker(&d->m_mutex); + if (!(d->state & Finished)) { + d->state = State((d->state & ~Running) | Finished); + d->waitCondition.wakeAll(); + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); + } +} + +void QFutureInterfaceBase::setExpectedResultCount(int resultCount) +{ + if (d->manualProgress == false) + setProgressRange(0, resultCount); + d->m_expectedResultCount = resultCount; +} + +int QFutureInterfaceBase::expectedResultCount() +{ + return d->m_expectedResultCount; +} + +bool QFutureInterfaceBase::queryState(State state) const +{ + return (d->state & state); +} + +void QFutureInterfaceBase::waitForResult(int resultIndex) +{ + d->m_exceptionStore.throwPossibleException(); + + if (!(d->state & Running)) + return; + + // To avoid deadlocks and reduce the number of threads used, try to + // run the runnable in the current thread. + QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); + + QMutexLocker lock(&d->m_mutex); + + if (!(d->state & Running)) + return; + + const int waitIndex = (resultIndex == -1) ? INT_MAX : resultIndex; + while ((d->state & Running) && d->internal_isResultReadyAt(waitIndex) == false) + d->waitCondition.wait(&d->m_mutex); + + d->m_exceptionStore.throwPossibleException(); +} + +void QFutureInterfaceBase::waitForFinished() +{ + if (d->state & Running) { + QThreadPool::globalInstance()->d_func()->stealRunnable(d->runnable); + + QMutexLocker lock(&d->m_mutex); + + while (d->state & Running) + d->waitCondition.wait(&d->m_mutex); + } + + d->m_exceptionStore.throwPossibleException(); +} + +void QFutureInterfaceBase::reportResultsReady(int beginIndex, int endIndex) +{ + if ((d->state & Canceled) || (d->state & Finished) || beginIndex == endIndex) + return; + + d->waitCondition.wakeAll(); + + if (d->manualProgress == false) { + if (d->internal_updateProgress(d->m_progressValue + endIndex - beginIndex) == false) { + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + beginIndex, + endIndex)); + return; + } + + d->sendCallOuts(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + d->m_progressValue, + d->m_progressText), + QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + beginIndex, + endIndex)); + return; + } + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, beginIndex, endIndex)); +} + +void QFutureInterfaceBase::setRunnable(QRunnable *runnable) +{ + d->runnable = runnable; +} + +void QFutureInterfaceBase::setFilterMode(bool enable) +{ + QMutexLocker locker(&d->m_mutex); + resultStoreBase().setFilterMode(enable); +} + +void QFutureInterfaceBase::setProgressRange(int minimum, int maximum) +{ + QMutexLocker locker(&d->m_mutex); + d->m_progressMinimum = minimum; + d->m_progressMaximum = maximum; + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, minimum, maximum)); +} + +void QFutureInterfaceBase::setProgressValue(int progressValue) +{ + setProgressValueAndText(progressValue, QString()); +} + +void QFutureInterfaceBase::setProgressValueAndText(int progressValue, + const QString &progressText) +{ + QMutexLocker locker(&d->m_mutex); + if (d->manualProgress == false) + d->manualProgress = true; + if (d->m_progressValue >= progressValue) + return; + + if ((d->state & Canceled) || (d->state & Finished)) + return; + + if (d->internal_updateProgress(progressValue, progressText)) { + d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + d->m_progressValue, + d->m_progressText)); + } +} + +QMutex *QFutureInterfaceBase::mutex() const +{ + return &d->m_mutex; +} + +QtConcurrent::internal::ExceptionStore &QFutureInterfaceBase::exceptionStore() +{ + return d->m_exceptionStore; +} + +QtConcurrent::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() +{ + return d->m_results; +} + +const QtConcurrent::ResultStoreBase &QFutureInterfaceBase::resultStoreBase() const +{ + return d->m_results; +} + +QFutureInterfaceBase &QFutureInterfaceBase::operator=(const QFutureInterfaceBase &other) +{ + other.d->refCount.ref(); + if (!d->refCount.deref()) + delete d; + d = other.d; + return *this; +} + +bool QFutureInterfaceBase::referenceCountIsOne() const +{ + return d->refCount == 1; +} + +QFutureInterfaceBasePrivate::QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState) + : refCount(1), m_progressValue(0), m_progressMinimum(0), m_progressMaximum(0), + state(initialState), pendingResults(0), + manualProgress(false), m_expectedResultCount(0), runnable(0) +{ + progressTime.invalidate(); +} + +int QFutureInterfaceBasePrivate::internal_resultCount() const +{ + return m_results.count(); // ### subtract canceled results. +} + +bool QFutureInterfaceBasePrivate::internal_isResultReadyAt(int index) const +{ + return (m_results.contains(index)); +} + +bool QFutureInterfaceBasePrivate::internal_waitForNextResult() +{ + if (m_results.hasNextResult()) + return true; + + while ((state & QFutureInterfaceBase::Running) && m_results.hasNextResult() == false) + waitCondition.wait(&m_mutex); + + return (!(state & QFutureInterfaceBase::Canceled) && m_results.hasNextResult()); +} + +bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress, + const QString &progressText) +{ + if (m_progressValue >= progress) + return false; + + m_progressValue = progress; + m_progressText = progressText; + + if (progressTime.isValid() && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. + if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) + return false; + + progressTime.start(); + return true; +} + +void QFutureInterfaceBasePrivate::internal_setThrottled(bool enable) +{ + // bail out if we are not changing the state + if ((enable && (state & QFutureInterfaceBase::Throttled)) + || (!enable && !(state & QFutureInterfaceBase::Throttled))) + return; + + // change the state + if (enable) { + state = QFutureInterfaceBase::State(state | QFutureInterfaceBase::Throttled); + } else { + state = QFutureInterfaceBase::State(state & ~QFutureInterfaceBase::Throttled); + if (!(state & QFutureInterfaceBase::Paused)) + pausedWaitCondition.wakeAll(); + } +} + +void QFutureInterfaceBasePrivate::sendCallOut(const QFutureCallOutEvent &callOutEvent) +{ + if (outputConnections.isEmpty()) + return; + + for (int i = 0; i < outputConnections.count(); ++i) + outputConnections.at(i)->postCallOutEvent(callOutEvent); +} + +void QFutureInterfaceBasePrivate::sendCallOuts(const QFutureCallOutEvent &callOutEvent1, + const QFutureCallOutEvent &callOutEvent2) +{ + if (outputConnections.isEmpty()) + return; + + for (int i = 0; i < outputConnections.count(); ++i) { + QFutureCallOutInterface *interface = outputConnections.at(i); + interface->postCallOutEvent(callOutEvent1); + interface->postCallOutEvent(callOutEvent2); + } +} + +// This function connects an output interface (for example a QFutureWatcher) +// to this future. While holding the lock we check the state and ready results +// and add the appropriate callouts to the queue. In order to avoid deadlocks, +// the actual callouts are made at the end while not holding the lock. +void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface *interface) +{ + QMutexLocker locker(&m_mutex); + + if (state & QFutureInterfaceBase::Started) { + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started)); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, + m_progressMinimum, + m_progressMaximum)); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress, + m_progressValue, + m_progressText)); + } + + QtConcurrent::ResultIteratorBase it = m_results.begin(); + while (it != m_results.end()) { + const int begin = it.resultIndex(); + const int end = begin + it.batchSize(); + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, + begin, + end)); + it.batchedAdvance(); + } + + if (state & QFutureInterfaceBase::Paused) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Paused)); + + if (state & QFutureInterfaceBase::Canceled) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled)); + + if (state & QFutureInterfaceBase::Finished) + interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished)); + + outputConnections.append(interface); +} + +void QFutureInterfaceBasePrivate::disconnectOutputInterface(QFutureCallOutInterface *interface) +{ + QMutexLocker lock(&m_mutex); + const int index = outputConnections.indexOf(interface); + if (index == -1) + return; + outputConnections.removeAt(index); + + interface->callOutInterfaceDisconnected(); +} + +void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState) +{ + state = newState; +} + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qfutureinterface.h b/src/corelib/concurrent/qfutureinterface.h new file mode 100644 index 0000000000..7f90519a74 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface.h @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREINTERFACE_H +#define QFUTUREINTERFACE_H + +#include +#include + +#ifndef QT_NO_QFUTURE + +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template class QFuture; +class QFutureInterfaceBasePrivate; +class QFutureWatcherBase; +class QFutureWatcherBasePrivate; + +class Q_CORE_EXPORT QFutureInterfaceBase +{ +public: + enum State { + NoState = 0x00, + Running = 0x01, + Started = 0x02, + Finished = 0x04, + Canceled = 0x08, + Paused = 0x10, + Throttled = 0x20 + }; + + QFutureInterfaceBase(State initialState = NoState); + QFutureInterfaceBase(const QFutureInterfaceBase &other); + virtual ~QFutureInterfaceBase(); + + // reporting functions available to the engine author: + void reportStarted(); + void reportFinished(); + void reportCanceled(); +#ifndef QT_NO_EXCEPTIONS + void reportException(const QtConcurrent::Exception &e); +#endif + void reportResultsReady(int beginIndex, int endIndex); + + void setRunnable(QRunnable *runnable); + void setFilterMode(bool enable); + void setProgressRange(int minimum, int maximum); + int progressMinimum() const; + int progressMaximum() const; + bool isProgressUpdateNeeded() const; + void setProgressValue(int progressValue); + int progressValue() const; + void setProgressValueAndText(int progressValue, const QString &progressText); + QString progressText() const; + + void setExpectedResultCount(int resultCount); + int expectedResultCount(); + int resultCount() const; + + bool queryState(State state) const; + bool isRunning() const; + bool isStarted() const; + bool isCanceled() const; + bool isFinished() const; + bool isPaused() const; + bool isThrottled() const; + bool isResultReadyAt(int index) const; + + void cancel(); + void setPaused(bool paused); + void togglePaused(); + void setThrottled(bool enable); + + void waitForFinished(); + bool waitForNextResult(); + void waitForResult(int resultIndex); + void waitForResume(); + + QMutex *mutex() const; + QtConcurrent::internal::ExceptionStore &exceptionStore(); + QtConcurrent::ResultStoreBase &resultStoreBase(); + const QtConcurrent::ResultStoreBase &resultStoreBase() const; + + inline bool operator==(const QFutureInterfaceBase &other) const { return d == other.d; } + inline bool operator!=(const QFutureInterfaceBase &other) const { return d != other.d; } + QFutureInterfaceBase &operator=(const QFutureInterfaceBase &other); + +protected: + bool referenceCountIsOne() const; +public: + +#ifndef QFUTURE_TEST +private: +#endif + QFutureInterfaceBasePrivate *d; + +private: + friend class QFutureWatcherBase; + friend class QFutureWatcherBasePrivate; +}; + +template +class QFutureInterface : public QFutureInterfaceBase +{ +public: + QFutureInterface(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { } + QFutureInterface(const QFutureInterface &other) + : QFutureInterfaceBase(other) + { } + ~QFutureInterface() + { + if (referenceCountIsOne()) + resultStore().clear(); + } + + static QFutureInterface canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface &operator=(const QFutureInterface &other) + { + if (referenceCountIsOne()) + resultStore().clear(); + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture future(); // implemented in qfuture.h + + inline void reportResult(const T *result, int index = -1); + inline void reportResult(const T &result, int index = -1); + inline void reportResults(const QVector &results, int beginIndex = -1, int count = -1); + inline void reportFinished(const T *result = 0); + + inline const T &resultReference(int index) const; + inline const T *resultPointer(int index) const; + inline QList results(); +private: + QtConcurrent::ResultStore &resultStore() + { return static_cast &>(resultStoreBase()); } + const QtConcurrent::ResultStore &resultStore() const + { return static_cast &>(resultStoreBase()); } +}; + +template +inline void QFutureInterface::reportResult(const T *result, int index) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtConcurrent::ResultStore &store = resultStore(); + + + if (store.filterMode()) { + const int resultCountBefore = store.count(); + store.addResult(index, result); + this->reportResultsReady(resultCountBefore, resultCountBefore + store.count()); + } else { + const int insertIndex = store.addResult(index, result); + this->reportResultsReady(insertIndex, insertIndex + 1); + } +} + +template +inline void QFutureInterface::reportResult(const T &result, int index) +{ + reportResult(&result, index); +} + +template +inline void QFutureInterface::reportResults(const QVector &_results, int beginIndex, int count) +{ + QMutexLocker locker(mutex()); + if (this->queryState(Canceled) || this->queryState(Finished)) { + return; + } + + QtConcurrent::ResultStore &store = resultStore(); + + if (store.filterMode()) { + const int resultCountBefore = store.count(); + store.addResults(beginIndex, &_results, count); + this->reportResultsReady(resultCountBefore, store.count()); + } else { + const int insertIndex = store.addResults(beginIndex, &_results, count); + this->reportResultsReady(insertIndex, insertIndex + _results.count()); + } +} + +template +inline void QFutureInterface::reportFinished(const T *result) +{ + if (result) + reportResult(result); + QFutureInterfaceBase::reportFinished(); +} + +template +inline const T &QFutureInterface::resultReference(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).value(); +} + +template +inline const T *QFutureInterface::resultPointer(int index) const +{ + QMutexLocker lock(mutex()); + return resultStore().resultAt(index).pointer(); +} + +template +inline QList QFutureInterface::results() +{ + if (this->isCanceled()) { + exceptionStore().throwPossibleException(); + return QList(); + } + QFutureInterfaceBase::waitForResult(-1); + + QList res; + QMutexLocker lock(mutex()); + + QtConcurrent::ResultIterator it = resultStore().begin(); + while (it != resultStore().end()) { + res.append(it.value()); + ++it; + } + + return res; +} + +template <> +class QFutureInterface : public QFutureInterfaceBase +{ +public: + QFutureInterface(State initialState = NoState) + : QFutureInterfaceBase(initialState) + { } + QFutureInterface(const QFutureInterface &other) + : QFutureInterfaceBase(other) + { } + + static QFutureInterface canceledResult() + { return QFutureInterface(State(Started | Finished | Canceled)); } + + QFutureInterface &operator=(const QFutureInterface &other) + { + QFutureInterfaceBase::operator=(other); + return *this; + } + + inline QFuture future(); // implemented in qfuture.h + + void reportResult(const void *, int) { } + void reportResults(const QVector &, int) { } + void reportFinished(void * = 0) { QFutureInterfaceBase::reportFinished(); } +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTUREINTERFACE_H diff --git a/src/corelib/concurrent/qfutureinterface_p.h b/src/corelib/concurrent/qfutureinterface_p.h new file mode 100644 index 0000000000..538947ead0 --- /dev/null +++ b/src/corelib/concurrent/qfutureinterface_p.h @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREINTERFACE_P_H +#define QFUTUREINTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QFutureCallOutEvent : public QEvent +{ +public: + enum CallOutType { + Started, + Finished, + Canceled, + Paused, + Resumed, + Progress, + ProgressRange, + ResultsReady + }; + + QFutureCallOutEvent() + : QEvent(QEvent::FutureCallOut), callOutType(CallOutType(0)), index1(-1), index2(-1) + { } + QFutureCallOutEvent(CallOutType callOutType, int index1 = -1) + : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(-1) + { } + QFutureCallOutEvent(CallOutType callOutType, int index1, int index2) + : QEvent(QEvent::FutureCallOut), callOutType(callOutType), index1(index1), index2(index2) + { } + + QFutureCallOutEvent(CallOutType callOutType, int index1, const QString &text) + : QEvent(QEvent::FutureCallOut), + callOutType(callOutType), + index1(index1), + index2(-1), + text(text) + { } + + CallOutType callOutType; + int index1; + int index2; + QString text; + + QFutureCallOutEvent *clone() const + { + return new QFutureCallOutEvent(callOutType, index1, index2, text); + } + +private: + QFutureCallOutEvent(CallOutType callOutType, + int index1, + int index2, + const QString &text) + : QEvent(QEvent::FutureCallOut), + callOutType(callOutType), + index1(index1), + index2(index2), + text(text) + { } +}; + +class QFutureCallOutInterface +{ +public: + virtual ~QFutureCallOutInterface() {} + virtual void postCallOutEvent(const QFutureCallOutEvent &) = 0; + virtual void callOutInterfaceDisconnected() = 0; +}; + +class QFutureInterfaceBasePrivate +{ +public: + QFutureInterfaceBasePrivate(QFutureInterfaceBase::State initialState); + + QAtomicInt refCount; + mutable QMutex m_mutex; + QWaitCondition waitCondition; + QList outputConnections; + int m_progressValue; + int m_progressMinimum; + int m_progressMaximum; + QFutureInterfaceBase::State state; + QElapsedTimer progressTime; + QWaitCondition pausedWaitCondition; + int pendingResults; + QtConcurrent::ResultStoreBase m_results; + bool manualProgress; + int m_expectedResultCount; + QtConcurrent::internal::ExceptionStore m_exceptionStore; + QString m_progressText; + QRunnable *runnable; + + // Internal functions that does not change the mutex state. + // The mutex must be locked when calling these. + int internal_resultCount() const; + bool internal_isResultReadyAt(int index) const; + bool internal_waitForNextResult(); + bool internal_updateProgress(int progress, const QString &progressText = QString()); + void internal_setThrottled(bool enable); + void sendCallOut(const QFutureCallOutEvent &callOut); + void sendCallOuts(const QFutureCallOutEvent &callOut1, const QFutureCallOutEvent &callOut2); + void connectOutputInterface(QFutureCallOutInterface *iface); + void disconnectOutputInterface(QFutureCallOutInterface *iface); + + void setState(QFutureInterfaceBase::State state); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/corelib/concurrent/qfuturesynchronizer.cpp b/src/corelib/concurrent/qfuturesynchronizer.cpp new file mode 100644 index 0000000000..b52e5fb73d --- /dev/null +++ b/src/corelib/concurrent/qfuturesynchronizer.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! \class QFutureSynchronizer + \since 4.4 + + \brief The QFutureSynchronizer class is a convenience class that simplifies + QFuture synchronization. + + \ingroup thread + + QFutureSynchronizer is a template class that simplifies synchronization of + one or more QFuture objects. Futures are added using the addFuture() or + setFuture() functions. The futures() function returns a list of futures. + Use clearFutures() to remove all futures from the QFutureSynchronizer. + + The waitForFinished() function waits for all futures to finish. + The destructor of QFutureSynchronizer calls waitForFinished(), providing + an easy way to ensure that all futures have finished before returning from + a function: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuturesynchronizer.cpp 0 + + The behavior of waitForFinished() can be changed using the + setCancelOnWait() function. Calling setCancelOnWait(true) will cause + waitForFinished() to cancel all futures before waiting for them to finish. + You can query the status of the cancel-on-wait feature using the + cancelOnWait() function. + + \sa QFuture, QFutureWatcher, {Concurrent Programming}{Qt Concurrent} +*/ + +/*! + \fn QFutureSynchronizer::QFutureSynchronizer() + + Constructs a QFutureSynchronizer. +*/ + +/*! + \fn QFutureSynchronizer::QFutureSynchronizer(const QFuture &future) + + Constructs a QFutureSynchronizer and begins watching \a future by calling + addFuture(). + + \sa addFuture() +*/ + +/*! + \fn QFutureSynchronizer::~QFutureSynchronizer() + + Calls waitForFinished() function to ensure that all futures have finished + before destroying this QFutureSynchronizer. + + \sa waitForFinished() +*/ + +/*! + \fn void QFutureSynchronizer::setFuture(const QFuture &future) + + Sets \a future to be the only future managed by this QFutureSynchronizer. + This is a convenience function that calls waitForFinished(), + then clearFutures(), and finally passes \a future to addFuture(). + + \sa addFuture(), waitForFinished(), clearFutures() +*/ + +/*! + \fn void QFutureSynchronizer::addFuture(const QFuture &future) + + Adds \a future to the list of managed futures. + + \sa futures() +*/ + +/*! + \fn void QFutureSynchronizer::waitForFinished() + + Waits for all futures to finish. If cancelOnWait() returns true, each + future is canceled before waiting for them to finish. + + \sa cancelOnWait(), setCancelOnWait() +*/ + +/*! + \fn void QFutureSynchronizer::clearFutures() + + Removes all managed futures from this QFutureSynchronizer. + + \sa addFuture(), setFuture() +*/ + +/*! + \fn QList > QFutureSynchronizer::futures() const + + Returns a list of all managed futures. + + \sa addFuture(), setFuture() +*/ + +/*! + \fn void QFutureSynchronizer::setCancelOnWait(bool enabled) + + Enables or disables the cancel-on-wait feature based on the \a enabled + argument. If \a enabled is true, the waitForFinished() function will cancel + all futures before waiting for them to finish. + + \sa waitForFinished() +*/ + +/*! + \fn bool QFutureSynchronizer::cancelOnWait() const + + Returns true if the cancel-on-wait feature is enabled; otherwise returns + false. If cancel-on-wait is enabled, the waitForFinished() function will + cancel all futures before waiting for them to finish. + + \sa waitForFinished() +*/ diff --git a/src/corelib/concurrent/qfuturesynchronizer.h b/src/corelib/concurrent/qfuturesynchronizer.h new file mode 100644 index 0000000000..23a2c242aa --- /dev/null +++ b/src/corelib/concurrent/qfuturesynchronizer.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTRUESYNCHRONIZER_H +#define QFUTRUESYNCHRONIZER_H + +#include + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template +class QFutureSynchronizer +{ + Q_DISABLE_COPY(QFutureSynchronizer) + +public: + QFutureSynchronizer() : m_cancelOnWait(false) { } + explicit QFutureSynchronizer(const QFuture &future) + : m_cancelOnWait(false) + { addFuture(future); } + ~QFutureSynchronizer() { waitForFinished(); } + + void setFuture(const QFuture &future) + { + waitForFinished(); + m_futures.clear(); + addFuture(future); + } + + void addFuture(const QFuture &future) + { + m_futures.append(future); + } + + void waitForFinished() + { + if (m_cancelOnWait) { + for (int i = 0; i < m_futures.count(); ++i) { + m_futures[i].cancel(); + } + } + + for (int i = 0; i < m_futures.count(); ++i) { + m_futures[i].waitForFinished(); + } + } + + void clearFutures() + { + m_futures.clear(); + } + + QList > futures() const + { + return m_futures; + } + + void setCancelOnWait(bool enabled) + { + m_cancelOnWait = enabled; + } + + bool cancelOnWait() const + { + return m_cancelOnWait; + } + +protected: + QList > m_futures; + bool m_cancelOnWait; +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTRUESYNCHRONIZER_H diff --git a/src/corelib/concurrent/qfuturewatcher.cpp b/src/corelib/concurrent/qfuturewatcher.cpp new file mode 100644 index 0000000000..ea12bc9302 --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher.cpp @@ -0,0 +1,592 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfuturewatcher.h" + +#ifndef QT_NO_QFUTURE + +#include +#include +#include + +#include "qfuturewatcher_p.h" + +QT_BEGIN_NAMESPACE + +/*! \class QFutureWatcher + \reentrant + \since 4.4 + + \ingroup thread + + \brief The QFutureWatcher class allows monitoring a QFuture using signals + and slots. + + QFutureWatcher provides information and notifications about a QFuture. Use + the setFuture() function to start watching a particular QFuture. The + future() function returns the future set with setFuture(). + + For convenience, several of QFuture's functions are also available in + QFutureWatcher: progressValue(), progressMinimum(), progressMaximum(), + progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), + isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), + setPaused(), pause(), resume(), and togglePaused() functions are slots in + QFutureWatcher. + + Status changes are reported via the started(), finished(), canceled(), + paused(), resumed(), resultReadyAt(), and resultsReadyAt() signals. + Progress information is provided from the progressRangeChanged(), + void progressValueChanged(), and progressTextChanged() signals. + + Throttling control is provided by the setPendingResultsLimit() function. + When the number of pending resultReadyAt() or resultsReadyAt() signals + exceeds the limit, the computation represented by the future will be + throttled automatically. The computation will resume once the number of + pending signals drops below the limit. + + Example: Starting a computation and getting a slot callback when it's + finished: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qfuturewatcher.cpp 0 + + Be aware that not all asynchronous computations can be canceled or paused. + For example, the future returned by QtConcurrent::run() cannot be + canceled; but the future returned by QtConcurrent::mappedReduced() can. + + QFutureWatcher is specialized to not contain any of the result + fetching functions. Any QFuture can be watched by a + QFutureWatcher as well. This is useful if only status or progress + information is needed; not the actual result data. + + \sa QFuture, {Concurrent Programming}{Qt Concurrent} +*/ + +/*! \fn QFutureWatcher::QFutureWatcher(QObject *parent) + + Constructs a new QFutureWatcher with the given \a parent. +*/ +QFutureWatcherBase::QFutureWatcherBase(QObject *parent) + :QObject(*new QFutureWatcherBasePrivate, parent) +{ } + +/*! \fn QFutureWatcher::~QFutureWatcher() + + Destroys the QFutureWatcher. +*/ + +/*! \fn void QFutureWatcher::cancel() + + Cancels the asynchronous computation represented by the future(). Note that + the cancelation is asynchronous. Use waitForFinished() after calling + cancel() when you need synchronous cancelation. + + Currently available results may still be accessed on a canceled QFuture, + but new results will \e not become available after calling this function. + Also, this QFutureWatcher will not deliver progress and result ready + signals once canceled. This includes the progressValueChanged(), + progressRangeChanged(), progressTextChanged(), resultReadyAt(), and + resultsReadyAt() signals. + + Be aware that not all asynchronous computations can be canceled. For + example, the QFuture returned by QtConcurrent::run() cannot be canceled; + but the QFuture returned by QtConcurrent::mappedReduced() can. +*/ +void QFutureWatcherBase::cancel() +{ + futureInterface().cancel(); +} + +/*! \fn void QFutureWatcher::setPaused(bool paused) + + If \a paused is true, this function pauses the asynchronous computation + represented by the future(). If the computation is already paused, this + function does nothing. This QFutureWatcher will stop delivering progress + and result ready signals while the future is paused. Signal delivery will + continue once the computation is resumed. + + If \a paused is false, this function resumes the asynchronous computation. + If the computation was not previously paused, this function does nothing. + + Be aware that not all computations can be paused. For example, the + QFuture returned by QtConcurrent::run() cannot be paused; but the QFuture + returned by QtConcurrent::mappedReduced() can. + + \sa pause(), resume(), togglePaused() +*/ +void QFutureWatcherBase::setPaused(bool paused) +{ + futureInterface().setPaused(paused); +} + +/*! \fn void QFutureWatcher::pause() + + Pauses the asynchronous computation represented by the future(). This is a + convenience method that simply calls setPaused(true). + + \sa resume() +*/ +void QFutureWatcherBase::pause() +{ + futureInterface().setPaused(true); +} + +/*! \fn void QFutureWatcher::resume() + + Resumes the asynchronous computation represented by the future(). This is + a convenience method that simply calls setPaused(false). + + \sa pause() +*/ +void QFutureWatcherBase::resume() +{ + futureInterface().setPaused(false); +} + +/*! \fn void QFutureWatcher::togglePaused() + + Toggles the paused state of the asynchronous computation. In other words, + if the computation is currently paused, calling this function resumes it; + if the computation is running, it becomes paused. This is a convenience + method for calling setPaused(!isPaused()). + + \sa setPaused(), pause(), resume() +*/ +void QFutureWatcherBase::togglePaused() +{ + futureInterface().togglePaused(); +} + +/*! \fn int QFutureWatcher::progressValue() const + + Returns the current progress value, which is between the progressMinimum() + and progressMaximum(). + + \sa progressMinimum(), progressMaximum() +*/ +int QFutureWatcherBase::progressValue() const +{ + return futureInterface().progressValue(); +} + +/*! \fn int QFutureWatcher::progressMinimum() const + + Returns the minimum progressValue(). + + \sa progressValue(), progressMaximum() +*/ +int QFutureWatcherBase::progressMinimum() const +{ + return futureInterface().progressMinimum(); +} + +/*! \fn int QFutureWatcher::progressMaximum() const + + Returns the maximum progressValue(). + + \sa progressValue(), progressMinimum() +*/ +int QFutureWatcherBase::progressMaximum() const +{ + return futureInterface().progressMaximum(); +} + +/*! \fn QString QFutureWatcher::progressText() const + + Returns the (optional) textual representation of the progress as reported + by the asynchronous computation. + + Be aware that not all computations provide a textual representation of the + progress, and as such, this function may return an empty string. +*/ +QString QFutureWatcherBase::progressText() const +{ + return futureInterface().progressText(); +} + +/*! \fn bool QFutureWatcher::isStarted() const + + Returns true if the asynchronous computation represented by the future() + has been started; otherwise returns false. +*/ +bool QFutureWatcherBase::isStarted() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Started); +} + +/*! \fn bool QFutureWatcher::isFinished() const + + Returns true if the asynchronous computation represented by the future() + has finished; otherwise returns false. +*/ +bool QFutureWatcherBase::isFinished() const +{ + Q_D(const QFutureWatcherBase); + return d->finished; +} + +/*! \fn bool QFutureWatcher::isRunning() const + + Returns true if the asynchronous computation represented by the future() + is currently running; otherwise returns false. +*/ +bool QFutureWatcherBase::isRunning() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Running); +} + +/*! \fn bool QFutureWatcher::isCanceled() const + + Returns true if the asynchronous computation has been canceled with the + cancel() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See cancel() for more details. +*/ +bool QFutureWatcherBase::isCanceled() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Canceled); +} + +/*! \fn bool QFutureWatcher::isPaused() const + + Returns true if the asynchronous computation has been paused with the + pause() function; otherwise returns false. + + Be aware that the computation may still be running even though this + function returns true. See setPaused() for more details. + + \sa setPaused(), togglePaused() +*/ +bool QFutureWatcherBase::isPaused() const +{ + return futureInterface().queryState(QFutureInterfaceBase::Paused); +} + +/*! \fn void QFutureWatcher::waitForFinished() + + Waits for the asynchronous computation to finish (including cancel()ed + computations). +*/ +void QFutureWatcherBase::waitForFinished() +{ + futureInterface().waitForFinished(); +} + +/*! \fn void QFutureWatcher::setPendingResultsLimit(int limit) + + The setPendingResultsLimit() provides throttling control. When the number + of pending resultReadyAt() or resultsReadyAt() signals exceeds the + \a limit, the computation represented by the future will be throttled + automatically. The computation will resume once the number of pending + signals drops below the \a limit. +*/ + +bool QFutureWatcherBase::event(QEvent *event) +{ + Q_D(QFutureWatcherBase); + if (event->type() == QEvent::FutureCallOut) { + QFutureCallOutEvent *callOutEvent = static_cast(event); + + if (futureInterface().isPaused()) { + d->pendingCallOutEvents.append(callOutEvent->clone()); + return true; + } + + if (callOutEvent->callOutType == QFutureCallOutEvent::Resumed + && !d->pendingCallOutEvents.isEmpty()) { + // send the resume + d->sendCallOutEvent(callOutEvent); + + // next send all pending call outs + for (int i = 0; i < d->pendingCallOutEvents.count(); ++i) + d->sendCallOutEvent(d->pendingCallOutEvents.at(i)); + qDeleteAll(d->pendingCallOutEvents); + d->pendingCallOutEvents.clear(); + } else { + d->sendCallOutEvent(callOutEvent); + } + return true; + } + return QObject::event(event); +} + +void QFutureWatcherBase::setPendingResultsLimit(int limit) +{ + Q_D(QFutureWatcherBase); + d->maximumPendingResultsReady = limit; +} + +void QFutureWatcherBase::connectNotify(const char * signal) +{ + Q_D(QFutureWatcherBase); + if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0) + d->resultAtConnected.ref(); +#ifndef QT_NO_DEBUG + if (qstrcmp(signal, SIGNAL(finished())) == 0) { + if (futureInterface().isRunning()) { + //connections should be established before calling stFuture to avoid race. + // (The future could finish before the connection is made.) + qWarning("QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race"); + } + } +#endif +} + +void QFutureWatcherBase::disconnectNotify(const char * signal) +{ + Q_D(QFutureWatcherBase); + if (qstrcmp(signal, SIGNAL(resultReadyAt(int))) == 0) + d->resultAtConnected.deref(); +} + +/*! + \internal +*/ +QFutureWatcherBasePrivate::QFutureWatcherBasePrivate() + : maximumPendingResultsReady(QThread::idealThreadCount() * 2), + resultAtConnected(0) +{ } + +/*! + \internal +*/ +void QFutureWatcherBase::connectOutputInterface() +{ + futureInterface().d->connectOutputInterface(d_func()); +} + +/*! + \internal +*/ +void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment) +{ + if (pendingAssignment) { + Q_D(QFutureWatcherBase); + d->pendingResultsReady = 0; + qDeleteAll(d->pendingCallOutEvents); + d->pendingCallOutEvents.clear(); + d->finished = false; + } + + futureInterface().d->disconnectOutputInterface(d_func()); +} + +void QFutureWatcherBasePrivate::postCallOutEvent(const QFutureCallOutEvent &callOutEvent) +{ + Q_Q(QFutureWatcherBase); + + if (callOutEvent.callOutType == QFutureCallOutEvent::ResultsReady) { + if (pendingResultsReady.fetchAndAddRelaxed(1) >= maximumPendingResultsReady) + q->futureInterface().d->internal_setThrottled(true); + } + + QCoreApplication::postEvent(q, callOutEvent.clone()); +} + +void QFutureWatcherBasePrivate::callOutInterfaceDisconnected() +{ + QCoreApplication::removePostedEvents(q_func(), QEvent::FutureCallOut); +} + +void QFutureWatcherBasePrivate::sendCallOutEvent(QFutureCallOutEvent *event) +{ + Q_Q(QFutureWatcherBase); + + switch (event->callOutType) { + case QFutureCallOutEvent::Started: + emit q->started(); + break; + case QFutureCallOutEvent::Finished: + finished = true; + emit q->finished(); + break; + case QFutureCallOutEvent::Canceled: + pendingResultsReady = 0; + emit q->canceled(); + break; + case QFutureCallOutEvent::Paused: + if (q->futureInterface().isCanceled()) + break; + emit q->paused(); + break; + case QFutureCallOutEvent::Resumed: + if (q->futureInterface().isCanceled()) + break; + emit q->resumed(); + break; + case QFutureCallOutEvent::ResultsReady: { + if (q->futureInterface().isCanceled()) + break; + + if (pendingResultsReady.fetchAndAddRelaxed(-1) <= maximumPendingResultsReady) + q->futureInterface().setThrottled(false); + + const int beginIndex = event->index1; + const int endIndex = event->index2; + + emit q->resultsReadyAt(beginIndex, endIndex); + + if (int(resultAtConnected) <= 0) + break; + + for (int i = beginIndex; i < endIndex; ++i) + emit q->resultReadyAt(i); + + } break; + case QFutureCallOutEvent::Progress: + if (q->futureInterface().isCanceled()) + break; + + emit q->progressValueChanged(event->index1); + if (!event->text.isNull()) // ### + q->progressTextChanged(event->text); + break; + case QFutureCallOutEvent::ProgressRange: + emit q->progressRangeChanged(event->index1, event->index2); + break; + default: break; + } +} + + +/*! \fn const T &QFutureWatcher::result() const + + Returns the first result in the future(). If the result is not immediately + available, this function will block and wait for the result to become + available. This is a convenience method for calling resultAt(0). + + \sa resultAt() +*/ + +/*! \fn const T &QFutureWatcher::resultAt(int index) const + + Returns the result at \a index in the future(). If the result is not + immediately available, this function will block and wait for the result to + become available. + + \sa result() +*/ + +/*! \fn void QFutureWatcher::setFuture(const QFuture &future) + + Starts watching the given \a future. + + One of the signals might be emitted for the current state of the + \a future. For example, if the future is already stopped, the + finished signal will be emitted. + + To avoid a race condition, it is important to call this function + \e after doing the connections. +*/ + +/*! \fn QFuture QFutureWatcher::future() const + + Returns the watched future. +*/ + +/*! \fn void QFutureWatcher::started() + + This signal is emitted when this QFutureWatcher starts watching the future + set with setFuture(). +*/ + +/*! + \fn void QFutureWatcher::finished() + This signal is emitted when the watched future finishes. +*/ + +/*! + \fn void QFutureWatcher::canceled() + This signal is emitted if the watched future is canceled. +*/ + +/*! \fn void QFutureWatcher::paused() + This signal is emitted when the watched future is paused. +*/ + +/*! \fn void QFutureWatcher::resumed() + This signal is emitted when the watched future is resumed. +*/ + +/*! + \fn void QFutureWatcher::progressRangeChanged(int minimum, int maximum) + + The progress range for the watched future has changed to \a minimum and + \a maximum +*/ + +/*! + \fn void QFutureWatcher::progressValueChanged(int progressValue) + + This signal is emitted when the watched future reports progress, + \a progressValue gives the current progress. In order to avoid overloading + the GUI event loop, QFutureWatcher limits the progress signal emission + rate. This means that listeners connected to this slot might not get all + progress reports the future makes. The last progress update (where + \a progressValue equals the maximum value) will always be delivered. +*/ + +/*! \fn void QFutureWatcher::progressTextChanged(const QString &progressText) + + This signal is emitted when the watched future reports textual progress + information, \a progressText. +*/ + +/*! + \fn void QFutureWatcher::resultReadyAt(int index) + + This signal is emitted when the watched future reports a ready result at + \a index. If the future reports multiple results, the index will indicate + which one it is. Results can be reported out-of-order. To get the result, + call future().result(index); +*/ + +/*! + \fn void QFutureWatcher::resultsReadyAt(int beginIndex, int endIndex); + + This signal is emitted when the watched future reports ready results. + The results are indexed from \a beginIndex to \a endIndex. + +*/ + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qfuturewatcher.h b/src/corelib/concurrent/qfuturewatcher.h new file mode 100644 index 0000000000..5fe2007a01 --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREWATCHER_H +#define QFUTUREWATCHER_H + +#include + +#ifndef QT_NO_QFUTURE + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QEvent; + +class QFutureWatcherBasePrivate; +class Q_CORE_EXPORT QFutureWatcherBase : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QFutureWatcherBase) + +public: + QFutureWatcherBase(QObject *parent = 0); + + int progressValue() const; + int progressMinimum() const; + int progressMaximum() const; + QString progressText() const; + + bool isStarted() const; + bool isFinished() const; + bool isRunning() const; + bool isCanceled() const; + bool isPaused() const; + + void waitForFinished(); + + void setPendingResultsLimit(int limit); + + bool event(QEvent *event); + +Q_SIGNALS: + void started(); + void finished(); + void canceled(); + void paused(); + void resumed(); + void resultReadyAt(int resultIndex); + void resultsReadyAt(int beginIndex, int endIndex); + void progressRangeChanged(int minimum, int maximum); + void progressValueChanged(int progressValue); + void progressTextChanged(const QString &progressText); + +public Q_SLOTS: + void cancel(); + void setPaused(bool paused); + void pause(); + void resume(); + void togglePaused(); + +protected: + void connectNotify (const char * signal); + void disconnectNotify (const char * signal); + + // called from setFuture() implemented in template sub-classes + void connectOutputInterface(); + void disconnectOutputInterface(bool pendingAssignment = false); + +private: + // implemented in the template sub-classes + virtual const QFutureInterfaceBase &futureInterface() const = 0; + virtual QFutureInterfaceBase &futureInterface() = 0; +}; + +template +class QFutureWatcher : public QFutureWatcherBase +{ +public: + QFutureWatcher(QObject *_parent = 0) + : QFutureWatcherBase(_parent) + { } + ~QFutureWatcher() + { disconnectOutputInterface(); } + + void setFuture(const QFuture &future); + QFuture future() const + { return m_future; } + + T result() const { return m_future.result(); } + T resultAt(int index) const { return m_future.resultAt(index); } + +#ifdef qdoc + int progressValue() const; + int progressMinimum() const; + int progressMaximum() const; + QString progressText() const; + + bool isStarted() const; + bool isFinished() const; + bool isRunning() const; + bool isCanceled() const; + bool isPaused() const; + + void waitForFinished(); + + void setPendingResultsLimit(int limit); + +Q_SIGNALS: + void started(); + void finished(); + void canceled(); + void paused(); + void resumed(); + void resultReadyAt(int resultIndex); + void resultsReadyAt(int beginIndex, int endIndex); + void progressRangeChanged(int minimum, int maximum); + void progressValueChanged(int progressValue); + void progressTextChanged(const QString &progressText); + +public Q_SLOTS: + void cancel(); + void setPaused(bool paused); + void pause(); + void resume(); + void togglePaused(); +#endif + +private: + QFuture m_future; + const QFutureInterfaceBase &futureInterface() const { return m_future.d; } + QFutureInterfaceBase &futureInterface() { return m_future.d; } +}; + +template +Q_INLINE_TEMPLATE void QFutureWatcher::setFuture(const QFuture &_future) +{ + if (_future == m_future) + return; + + disconnectOutputInterface(true); + m_future = _future; + connectOutputInterface(); +} + +template <> +class QFutureWatcher : public QFutureWatcherBase +{ +public: + QFutureWatcher(QObject *_parent = 0) + : QFutureWatcherBase(_parent) + { } + ~QFutureWatcher() + { disconnectOutputInterface(); } + + void setFuture(const QFuture &future); + QFuture future() const + { return m_future; } + +private: + QFuture m_future; + const QFutureInterfaceBase &futureInterface() const { return m_future.d; } + QFutureInterfaceBase &futureInterface() { return m_future.d; } +}; + +Q_INLINE_TEMPLATE void QFutureWatcher::setFuture(const QFuture &_future) +{ + if (_future == m_future) + return; + + disconnectOutputInterface(true); + m_future = _future; + connectOutputInterface(); +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif // QFUTUREWATCHER_H diff --git a/src/corelib/concurrent/qfuturewatcher_p.h b/src/corelib/concurrent/qfuturewatcher_p.h new file mode 100644 index 0000000000..fd02d44773 --- /dev/null +++ b/src/corelib/concurrent/qfuturewatcher_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFUTUREWATCHER_P_H +#define QFUTUREWATCHER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfutureinterface_p.h" +#include + +#ifndef QT_NO_QFUTURE + +#include + +QT_BEGIN_NAMESPACE + +class QFutureWatcherBase; +class QFutureWatcherBasePrivate : public QObjectPrivate, + public QFutureCallOutInterface +{ + Q_DECLARE_PUBLIC(QFutureWatcherBase) + +public: + QFutureWatcherBasePrivate(); + + void postCallOutEvent(const QFutureCallOutEvent &callOutEvent); + void callOutInterfaceDisconnected(); + + void sendCallOutEvent(QFutureCallOutEvent *event); + + QList pendingCallOutEvents; + QAtomicInt pendingResultsReady; + int maximumPendingResultsReady; + + QAtomicInt resultAtConnected; + bool finished; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_QFUTURE +#endif diff --git a/src/corelib/concurrent/qrunnable.cpp b/src/corelib/concurrent/qrunnable.cpp new file mode 100644 index 0000000000..1aa7d59986 --- /dev/null +++ b/src/corelib/concurrent/qrunnable.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QRunnable + \since 4.4 + \brief The QRunnable class is the base class for all runnable objects. + + \ingroup thread + + The QRunnable class is an interface for representing a task or + piece of code that needs to be executed, represented by your + reimplementation of the run() function. + + You can use QThreadPool to execute your code in a separate + thread. QThreadPool deletes the QRunnable automatically if + autoDelete() returns true (the default). Use setAutoDelete() to + change the auto-deletion flag. + + QThreadPool supports executing the same QRunnable more than once + by calling QThreadPool::tryStart(this) from within the run() function. + If autoDelete is enabled the QRunnable will be deleted when + the last thread exits the run function. Calling QThreadPool::start() + multiple times with the same QRunnable when autoDelete is enabled + creates a race condition and is not recommended. + + \sa QThreadPool +*/ + +/*! \fn QRunnable::run() + Implement this pure virtual function in your subclass. +*/ + +/*! \fn QRunnable::QRunnable() + Constructs a QRunnable. Auto-deletion is enabled by default. + + \sa autoDelete(), setAutoDelete() +*/ + +/*! \fn QRunnable::~QRunnable() + QRunnable virtual destructor. +*/ + +/*! \fn bool QRunnable::autoDelete() const + + Returns true is auto-deletion is enabled; false otherwise. + + If auto-deletion is enabled, QThreadPool will automatically delete + this runnable after calling run(); otherwise, ownership remains + with the application programmer. + + \sa setAutoDelete(), QThreadPool +*/ + +/*! \fn bool QRunnable::setAutoDelete(bool autoDelete) + + Enables auto-deletion if \a autoDelete is true; otherwise + auto-deletion is disabled. + + If auto-deletion is enabled, QThreadPool will automatically delete + this runnable after calling run(); otherwise, ownership remains + with the application programmer. + + Note that this flag must be set before calling + QThreadPool::start(). Calling this function after + QThreadPool::start() results in undefined behavior. + + \sa autoDelete(), QThreadPool +*/ diff --git a/src/corelib/concurrent/qrunnable.h b/src/corelib/concurrent/qrunnable.h new file mode 100644 index 0000000000..c4eea1184f --- /dev/null +++ b/src/corelib/concurrent/qrunnable.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRUNNABLE_H +#define QRUNNABLE_H + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QRunnable +{ + int ref; + + friend class QThreadPool; + friend class QThreadPoolPrivate; + friend class QThreadPoolThread; + +public: + virtual void run() = 0; + + QRunnable() : ref(0) { } + virtual ~QRunnable() { } + + bool autoDelete() const { return ref != -1; } + void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; } +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif diff --git a/src/corelib/concurrent/qtconcurrentcompilertest.h b/src/corelib/concurrent/qtconcurrentcompilertest.h new file mode 100644 index 0000000000..fad0c35109 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentcompilertest.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_COMPILERTEST_H +#define QTCONCURRENT_COMPILERTEST_H + +#include + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#if defined (Q_CC_MSVC) && (_MSC_VER < 1300) +# define QT_TYPENAME +#else +# define QT_TYPENAME typename +#endif + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentexception.cpp b/src/corelib/concurrent/qtconcurrentexception.cpp new file mode 100644 index 0000000000..b4123f52ca --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentexception.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentexception.h" + +#ifndef QT_NO_QFUTURE +#ifndef QT_NO_EXCEPTIONS + +QT_BEGIN_NAMESPACE + +/*! + \class QtConcurrent::Exception + \brief The Exception class provides a base class for exceptions that can transferred across threads. + \since 4.4 + + Qt Concurrent supports throwing and catching exceptions across thread + boundaries, provided that the exception inherit from QtConcurrent::Exception + and implement two helper functions: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 0 + + QtConcurrent::Exception subclasses must be thrown by value and + caught by reference: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 1 + + If you throw an exception that is not a subclass of QtConcurrent::Exception, + the Qt Concurrent functions will throw a QtConcurrent::UnhandledException + in the receiver thread. + + When using QFuture, transferred exceptions will be thrown when calling the following functions: + \list + \o QFuture::waitForFinished() + \o QFuture::result() + \o QFuture::resultAt() + \o QFuture::results() + \endlist +*/ + +/*! + \fn QtConcurrent::Exception::raise() const + In your QtConcurrent::Exception subclass, reimplement raise() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 2 +*/ + +/*! + \fn QtConcurrent::Exception::clone() const + In your QtConcurrent::Exception subclass, reimplement clone() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentexception.cpp 3 +*/ + +/*! + \class QtConcurrent::UnhandledException + + \brief The UnhandledException class represents an unhandled exception in a worker thread. + \since 4.4 + + If a worker thread throws an exception that is not a subclass of QtConcurrent::Exception, + the Qt Concurrent functions will throw a QtConcurrent::UnhandledException + on the receiver thread side. + + Inheriting from this class is not supported. +*/ + +/*! + \fn QtConcurrent::UnhandledException::raise() const + \internal +*/ + +/*! + \fn QtConcurrent::UnhandledException::clone() const + \internal +*/ + +namespace QtConcurrent +{ + +void Exception::raise() const +{ + Exception e = *this; + throw e; +} + +Exception *Exception::clone() const +{ + return new Exception(*this); +} + +void UnhandledException::raise() const +{ + UnhandledException e = *this; + throw e; +} + +Exception *UnhandledException::clone() const +{ + return new UnhandledException(*this); +} + +#ifndef qdoc + +namespace internal { + +class Base +{ +public: + Base(Exception *exception) + : exception(exception), refCount(1), hasThrown(false) { } + ~Base() { delete exception; } + + Exception *exception; + QAtomicInt refCount; + bool hasThrown; +}; + +ExceptionHolder::ExceptionHolder(Exception *exception) +: base(new Base(exception)) {} + +ExceptionHolder::ExceptionHolder(const ExceptionHolder &other) +: base(other.base) +{ + base->refCount.ref(); +} + +void ExceptionHolder::operator=(const ExceptionHolder &other) +{ + if (base == other.base) + return; + + if (base->refCount.deref() == false) + delete base; + + base = other.base; + base->refCount.ref(); +} + +ExceptionHolder::~ExceptionHolder() +{ + if (base->refCount.deref() == 0) + delete base; +} + +Exception *ExceptionHolder::exception() const +{ + return base->exception; +} + +void ExceptionStore::setException(const Exception &e) +{ + if (hasException() == false) + exceptionHolder = ExceptionHolder(e.clone()); +} + +bool ExceptionStore::hasException() const +{ + return (exceptionHolder.exception() != 0); +} + +ExceptionHolder ExceptionStore::exception() +{ + return exceptionHolder; +} + +void ExceptionStore::throwPossibleException() +{ + if (hasException() ) { + exceptionHolder.base->hasThrown = true; + exceptionHolder.exception()->raise(); + } +} + +bool ExceptionStore::hasThrown() const { return exceptionHolder.base->hasThrown; } + +} // namespace internal + +#endif //qdoc + +} // namespace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_EXCEPTIONS +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentexception.h b/src/corelib/concurrent/qtconcurrentexception.h new file mode 100644 index 0000000000..044b100e99 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentexception.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_EXCEPTION_H +#define QTCONCURRENT_EXCEPTION_H + +#include + +#ifndef QT_NO_QFUTURE + +#include + +#ifndef QT_NO_EXCEPTIONS +# include +#endif + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +namespace QtConcurrent +{ + +#ifndef QT_NO_EXCEPTIONS + +class Q_CORE_EXPORT Exception : public std::exception +{ +public: + virtual void raise() const; + virtual Exception *clone() const; +}; + +class Q_CORE_EXPORT UnhandledException : public Exception +{ +public: + void raise() const; + Exception *clone() const; +}; + +namespace internal { + +class Base; +class ExceptionHolder +{ +public: + ExceptionHolder(Exception *exception = 0); + ExceptionHolder(const ExceptionHolder &other); + void operator=(const ExceptionHolder &other); + ~ExceptionHolder(); + Exception *exception() const; + Base *base; +}; + +class Q_CORE_EXPORT ExceptionStore +{ +public: + void setException(const Exception &e); + bool hasException() const; + ExceptionHolder exception(); + void throwPossibleException(); + bool hasThrown() const; + ExceptionHolder exceptionHolder; +}; + +} // namespace internal + +#else // QT_NO_EXCEPTIONS + +namespace internal { + +class Q_CORE_EXPORT ExceptionStore +{ +public: + ExceptionStore() { } + inline void throwPossibleException() const {} +}; + +} // namespace internal + +#endif + +} // namespace QtConcurrent + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfilter.cpp b/src/corelib/concurrent/qtconcurrentfilter.cpp new file mode 100644 index 0000000000..6646e02afc --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilter.cpp @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \headerfile + \title Concurrent Filter and Filter-Reduce + \ingroup thread + + \brief The header provides concurrent Filter and + Filter-Reduce. + + These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework. + + The QtConcurrent::filter(), QtConcurrent::filtered() and + QtConcurrent::filteredReduced() functions filter items in a sequence such + as a QList or a QVector in parallel. QtConcurrent::filter() modifies a + sequence in-place, QtConcurrent::filtered() returns a new sequence + containing the filtered content, and QtConcurrent::filteredReduced() + returns a single result. + + Each of the above functions have a blocking variant that returns the final + result instead of a QFuture. You use them in the same way as the + asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 6 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QStringList and QSet). + + \section1 Concurrent Filter + + QtConcurrent::filtered() takes an input sequence and a filter function. + This filter function is then called for each item in the sequence, and a + new sequence containing the filtered values is returned. + + The filter function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 0 + + T must match the type stored in the sequence. The function returns true if + the item should be kept, false if it should be discarded. + + This example shows how to keep strings that are all lower-case from a + QStringList: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 1 + + The results of the filter are made available through QFuture. See the + QFuture and QFutureWatcher documentation for more information on how to + use QFuture in your applications. + + If you want to modify a sequence in-place, use QtConcurrent::filter(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 2 + + Since the sequence is modified in place, QtConcurrent::filter() does not + return any results via QFuture. However, you can still use QFuture and + QFutureWatcher to monitor the status of the filter. + + \section1 Concurrent Filter-Reduce + + QtConcurrent::filteredReduced() is similar to QtConcurrent::filtered(), + but instead of returing a sequence with the filtered results, the results + are combined into a single value using a reduce function. + + The reduce function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 3 + + T is the type of the final result, U is the type of items being filtered. + Note that the return value and return type of the reduce function are not + used. + + Call QtConcurrent::filteredReduced() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 4 + + The reduce function will be called once for each result kept by the filter + function, and should merge the \e{intermediate} into the \e{result} + variable. QtConcurrent::filteredReduced() guarantees that only one thread + will call reduce at a time, so using a mutex to lock the result variable + is not necessary. The QtConcurrent::ReduceOptions enum provides a way to + control the order in which the reduction is done. + + \section1 Additional API Features + + \section2 Using Iterators instead of Sequence + + Each of the above functions has a variant that takes an iterator range + instead of a sequence. You use them in the same way as the sequence + variants: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 5 + + + \section2 Using Member Functions + + QtConcurrent::filter(), QtConcurrent::filtered(), and + QtConcurrent::filteredReduced() accept pointers to member functions. + The member function class type must match the type stored in the sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 7 + + Note that when using QtConcurrent::filteredReduced(), you can mix the use of + normal and member functions freely: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 8 + + \section2 Using Function Objects + + QtConcurrent::filter(), QtConcurrent::filtered(), and + QtConcurrent::filteredReduced() accept function objects, which can be used to + add state to a function call. The result_type typedef must define the + result type of the function call operator: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 13 + + \section2 Using Bound Function Arguments + + Note that Qt does not provide support for bound functions. This is + provided by 3rd party libraries like + \l{http://www.boost.org/libs/bind/bind.html}{Boost} or + \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf} + {C++ TR1 Library Extensions}. + + If you want to use a filter function takes more than one argument, you can + use boost::bind() or std::tr1::bind() to transform it onto a function that + takes one argument. + + As an example, we use QString::contains(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 9 + + QString::contains() takes 2 arguments (including the "this" pointer) and + can't be used with QtConcurrent::filtered() directly, because + QtConcurrent::filtered() expects a function that takes one argument. To + use QString::contains() with QtConcurrent::filtered() we have to provide a + value for the \e regexp argument: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 10 + + The return value from boost::bind() is a function object (functor) with + the following signature: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 11 + + This matches what QtConcurrent::filtered() expects, and the complete + example becomes: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentfilter.cpp 12 +*/ + +/*! + \fn QFuture QtConcurrent::filter(Sequence &sequence, FilterFunction filterFunction) + \relates + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true, the item is kept in \a sequence; + otherwise, the item is removed from \a sequence. +*/ + +/*! + \fn QFuture QtConcurrent::filtered(const Sequence &sequence, FilterFunction filterFunction) + \relates + + Calls \a filterFunction once for each item in \a sequence and returns a + new Sequence of kept items. If \a filterFunction returns true, a copy of + the item is put in the new Sequence. Otherwise, the item will \e not + appear in the new Sequence. +*/ + +/*! + \fn QFuture QtConcurrent::filtered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction) + \relates + + Calls \a filterFunction once for each item from \a begin to \a end and + returns a new Sequence of kept items. If \a filterFunction returns true, a + copy of the item is put in the new Sequence. Otherwise, the item will + \e not appear in the new Sequence. +*/ + +/*! + \fn QFuture QtConcurrent::filteredReduced(const Sequence &sequence, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + \relates + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which \a reduceFunction + is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of + the original sequence. +*/ + +/*! + \fn QFuture QtConcurrent::filteredReduced(ConstIterator begin, ConstIterator end, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + \relates + + Calls \a filterFunction once for each item from \a begin to \a end. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which + \a reduceFunction is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order + of the original sequence. +*/ + +/*! + \fn void QtConcurrent::blockingFilter(Sequence &sequence, FilterFunction filterFunction) + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true, the item is kept in \a sequence; + otherwise, the item is removed from \a sequence. + + \note This function will block until all items in the sequence have been processed. +*/ + +/*! + \fn Sequence QtConcurrent::blockingFiltered(const Sequence &sequence, FilterFunction filterFunction) + + Calls \a filterFunction once for each item in \a sequence and returns a + new Sequence of kept items. If \a filterFunction returns true, a copy of + the item is put in the new Sequence. Otherwise, the item will \e not + appear in the new Sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa filtered() +*/ + +/*! + \fn Sequence QtConcurrent::blockingFiltered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction) + + Calls \a filterFunction once for each item from \a begin to \a end and + returns a new Sequence of kept items. If \a filterFunction returns true, a + copy of the item is put in the new Sequence. Otherwise, the item will + \e not appear in the new Sequence. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa filtered() +*/ + +/*! + \fn T QtConcurrent::blockingFilteredReduced(const Sequence &sequence, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + Calls \a filterFunction once for each item in \a sequence. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which \a reduceFunction + is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, \a reduceFunction is called in the order of + the original sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa filteredReduced() +*/ + +/*! + \fn T QtConcurrent::blockingFilteredReduced(ConstIterator begin, ConstIterator end, FilterFunction filterFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + Calls \a filterFunction once for each item from \a begin to \a end. If + \a filterFunction returns true for an item, that item is then passed to + \a reduceFunction. In other words, the return value is the result of + \a reduceFunction for each item where \a filterFunction returns true. + + Note that while \a filterFunction is called concurrently, only one thread + at a time will call \a reduceFunction. The order in which + \a reduceFunction is called is undefined if \a reduceOptions is + QtConcurrent::UnorderedReduce. If \a reduceOptions is + QtConcurrent::OrderedReduce, the \a reduceFunction is called in the order + of the original sequence. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa filteredReduced() +*/ diff --git a/src/corelib/concurrent/qtconcurrentfilter.h b/src/corelib/concurrent/qtconcurrentfilter.h new file mode 100644 index 0000000000..e392212b12 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilter.h @@ -0,0 +1,736 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FILTER_H +#define QTCONCURRENT_FILTER_H + +#include + +#ifndef QT_NO_CONCURRENT + +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef qdoc + +namespace QtConcurrent { + + QFuture filter(Sequence &sequence, FilterFunction filterFunction); + + template + QFuture filtered(const Sequence &sequence, FilterFunction filterFunction); + template + QFuture filtered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction); + + template + QFuture filteredReduced(const Sequence &sequence, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + template + QFuture filteredReduced(ConstIterator begin, + ConstIterator end, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + + void blockingFilter(Sequence &sequence, FilterFunction filterFunction); + + template + Sequence blockingFiltered(const Sequence &sequence, FilterFunction filterFunction); + template + Sequence blockingFiltered(ConstIterator begin, ConstIterator end, FilterFunction filterFunction); + + template + T blockingFilteredReduced(const Sequence &sequence, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + template + T blockingFilteredReduced(ConstIterator begin, + ConstIterator end, + FilterFunction filterFunction, + ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions = UnorderedReduce | SequentialReduce); + +} // namespace QtConcurrent + +#else + +namespace QtConcurrent { + +template +ThreadEngineStarter filterInternal(Sequence &sequence, KeepFunctor keep, T (C::*reduce)(U)) +{ + typedef MemberFunctionWrapper1 ReduceFunctor; + typedef typename Sequence::const_iterator Iterator; + typedef FilterKernel KernelType; + return startThreadEngine(new KernelType(sequence, keep, reduce)); +} + +// filter() on sequences +template +QFuture filter(Sequence &sequence, KeepFunctor keep) +{ + return filterInternal(sequence, keep, &Sequence::push_back); +} + +template +QFuture filter(Sequence &sequence, bool (keep)(T)) +{ + return filterInternal(sequence, FunctionWrapper1(keep), &Sequence::push_back); +} + +template +QFuture filter(Sequence &sequence, bool (C::*keep)() const) +{ + return filterInternal(sequence, ConstMemberFunctionWrapper(keep), &Sequence::push_back); +} + +// filteredReduced() on sequences +template +QFuture filteredReduced(const Sequence &sequence, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced(sequence, keep, reduce, options); + } + +template +QFuture filteredReduced(const Sequence &sequence, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + FunctionWrapper1(filter), + reduce, + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + ConstMemberFunctionWrapper(filter), + reduce, + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + keep, + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + keep, + MemberFunctionWrapper1(reduce), + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + FunctionWrapper1(keep), + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + ConstMemberFunctionWrapper(keep), + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + FunctionWrapper1(keep), + MemberFunctionWrapper1(reduce), + options); +} + +template +QFuture filteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(sequence, + ConstMemberFunctionWrapper(keep), + MemberFunctionWrapper1(reduce), + options); +} + +// filteredReduced() on iterators +template +QFuture filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced(begin, end, keep, reduce, options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + FunctionWrapper1(filter), + reduce, + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + ConstMemberFunctionWrapper(filter), + reduce, + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + keep, + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + keep, + MemberFunctionWrapper1(reduce), + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + FunctionWrapper1(keep), + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + ConstMemberFunctionWrapper(keep), + FunctionWrapper2(reduce), + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + FunctionWrapper1(keep), + MemberFunctionWrapper1(reduce), + options); +} + +template +QFuture filteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return filteredReduced(begin, + end, + ConstMemberFunctionWrapper(keep), + MemberFunctionWrapper1(reduce), + options); +} + + +// filtered() on sequences +template +QFuture filtered(const Sequence &sequence, KeepFunctor keep) +{ + return startFiltered(sequence, keep); +} + +template +QFuture filtered(const Sequence &sequence, bool (keep)(T)) +{ + return startFiltered(sequence, FunctionWrapper1(keep)); +} + +template +QFuture filtered(const Sequence &sequence, bool (C::*keep)() const) +{ + return startFiltered(sequence, ConstMemberFunctionWrapper(keep)); +} + +// filtered() on iterators +template +QFuture::value_type> filtered(Iterator begin, Iterator end, KeepFunctor keep) +{ + return startFiltered(begin, end, keep); +} + +template +QFuture::value_type> filtered(Iterator begin, Iterator end, bool (keep)(T)) +{ + return startFiltered(begin, end, FunctionWrapper1(keep)); +} + +template +QFuture::value_type> filtered(Iterator begin, + Iterator end, + bool (C::*keep)() const) +{ + return startFiltered(begin, end, ConstMemberFunctionWrapper(keep)); +} + + +// blocking filter() on sequences +template +void blockingFilter(Sequence &sequence, KeepFunctor keep) +{ + filterInternal(sequence, keep, &Sequence::push_back).startBlocking(); +} + +template +void blockingFilter(Sequence &sequence, bool (keep)(T)) +{ + filterInternal(sequence, FunctionWrapper1(keep), &Sequence::push_back) + .startBlocking(); +} + +template +void blockingFilter(Sequence &sequence, bool (C::*keep)() const) +{ + filterInternal(sequence, + ConstMemberFunctionWrapper(keep), + &Sequence::push_back) + .startBlocking(); +} + +// blocking filteredReduced() on sequences +template +ResultType blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced(sequence, keep, reduce, options) + .startBlocking(); +} + +template +ResultType blockingFilteredReduced(const Sequence &sequence, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + FunctionWrapper1(filter), + reduce, + options); +} + +template +ResultType blockingFilteredReduced(const Sequence &sequence, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + ConstMemberFunctionWrapper(filter), + reduce, + options); +} + +template +U blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + keep, + FunctionWrapper2(reduce), + options); +} + +template +C blockingFilteredReduced(const Sequence &sequence, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + keep, + MemberFunctionWrapper1(reduce), + options); +} + +template +V blockingFilteredReduced(const Sequence &sequence, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + FunctionWrapper1(keep), + FunctionWrapper2(reduce), + options); +} + +template +U blockingFilteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + ConstMemberFunctionWrapper(keep), + FunctionWrapper2(reduce), + options); +} + +template +C blockingFilteredReduced(const Sequence &sequence, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + FunctionWrapper1(keep), + MemberFunctionWrapper1(reduce), + options); +} + +template +D blockingFilteredReduced(const Sequence &sequence, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (sequence, + ConstMemberFunctionWrapper(keep), + MemberFunctionWrapper1(reduce), + options); +} + +// blocking filteredReduced() on iterators +template +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startFilteredReduced(begin, end, keep, reduce, options) + .startBlocking(); +} + +template +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + bool (filter)(T), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + FunctionWrapper1(filter), + reduce, + options); +} + +template +ResultType blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*filter)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + ConstMemberFunctionWrapper(filter), + reduce, + options); +} + +template +U blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + keep, + FunctionWrapper2(reduce), + options); +} + +template +C blockingFilteredReduced(Iterator begin, + Iterator end, + KeepFunctor keep, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + keep, + MemberFunctionWrapper1(reduce), + options); +} + +template +V blockingFilteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + FunctionWrapper1(keep), + FunctionWrapper2(reduce), + options); +} + +template +U blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + ConstMemberFunctionWrapper(keep), + FunctionWrapper2(reduce), + options); +} + +template +C blockingFilteredReduced(Iterator begin, + Iterator end, + bool (keep)(T), + U (C::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + FunctionWrapper1(keep), + MemberFunctionWrapper1(reduce), + options); +} + +template +D blockingFilteredReduced(Iterator begin, + Iterator end, + bool (C::*keep)() const, + T (D::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return blockingFilteredReduced + (begin, + end, + ConstMemberFunctionWrapper(keep), + MemberFunctionWrapper1(reduce), + options); +} + +// blocking filtered() on sequences +template +Sequence blockingFiltered(const Sequence &sequence, KeepFunctor keep) +{ + return blockingFilteredReduced(sequence, keep, &Sequence::push_back, OrderedReduce); +} + +template +Sequence blockingFiltered(const Sequence &sequence, bool (keep)(T)) +{ + return blockingFilteredReduced(sequence, keep, &Sequence::push_back, OrderedReduce); +} + +template +Sequence blockingFiltered(const Sequence &sequence, bool (C::*filter)() const) +{ + return blockingFilteredReduced(sequence, + filter, + &Sequence::push_back, + OrderedReduce); +} + +// blocking filtered() on iterators +template +OutputSequence blockingFiltered(Iterator begin, Iterator end, KeepFunctor keep) +{ + return blockingFilteredReduced(begin, + end, + keep, + &OutputSequence::push_back, + OrderedReduce); +} + +template +OutputSequence blockingFiltered(Iterator begin, Iterator end, bool (keep)(T)) +{ + return blockingFilteredReduced(begin, + end, + keep, + &OutputSequence::push_back, + OrderedReduce); +} + +template +OutputSequence blockingFiltered(Iterator begin, Iterator end, bool (C::*filter)() const) +{ + return blockingFilteredReduced(begin, + end, + filter, + &OutputSequence::push_back, + OrderedReduce); +} + +} // namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfilterkernel.h b/src/corelib/concurrent/qtconcurrentfilterkernel.h new file mode 100644 index 0000000000..cd926c006f --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfilterkernel.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FILTERKERNEL_H +#define QTCONCURRENT_FILTERKERNEL_H + +#include + +#ifndef QT_NO_CONCURRENT + +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template +struct qValueType +{ + typedef typename T::value_type value_type; +}; + +template +struct qValueType +{ + typedef T value_type; +}; + +template +struct qValueType +{ + typedef T value_type; +}; + +// Implementation of filter +template +class FilterKernel : public IterateKernel +{ + typedef ReduceKernel Reducer; + typedef IterateKernel IterateKernelType; + typedef typename ReduceFunctor::result_type T; + + Sequence reducedResult; + Sequence &sequence; + KeepFunctor keep; + ReduceFunctor reduce; + Reducer reducer; + +public: + FilterKernel(Sequence &_sequence, KeepFunctor _keep, ReduceFunctor _reduce) + : IterateKernelType(const_cast(_sequence).begin(), const_cast(_sequence).end()), reducedResult(), + sequence(_sequence), + keep(_keep), + reduce(_reduce), + reducer(OrderedReduce) + { } + + bool runIteration(typename Sequence::const_iterator it, int index, T *) + { + IntermediateResults results; + results.begin = index; + results.end = index + 1; + + if (keep(*it)) + results.vector.append(*it); + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + bool runIterations(typename Sequence::const_iterator sequenceBeginIterator, int begin, int end, T *) + { + IntermediateResults results; + results.begin = begin; + results.end = end; + results.vector.reserve(end - begin); + + + typename Sequence::const_iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + void finish() + { + reducer.finish(reduce, reducedResult); + sequence = reducedResult; + } + + inline bool shouldThrottleThread() + { + return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); + } + + inline bool shouldStartThread() + { + return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); + } + + typedef void ReturnType; + typedef void ResultType; +}; + +// Implementation of filter-reduce +template ::value_type> > +class FilteredReducedKernel : public IterateKernel +{ + ReducedResultType reducedResult; + KeepFunctor keep; + ReduceFunctor reduce; + Reducer reducer; + typedef IterateKernel IterateKernelType; + +public: + FilteredReducedKernel(Iterator begin, + Iterator end, + KeepFunctor _keep, + ReduceFunctor _reduce, + ReduceOptions reduceOption) + : IterateKernelType(begin, end), reducedResult(), keep(_keep), reduce(_reduce), reducer(reduceOption) + { } + +#if 0 + FilteredReducedKernel(ReducedResultType initialValue, + KeepFunctor keep, + ReduceFunctor reduce, + ReduceOption reduceOption) + : reducedResult(initialValue), keep(keep), reduce(reduce), reducer(reduceOption) + { } +#endif + + bool runIteration(Iterator it, int index, ReducedResultType *) + { + IntermediateResults::value_type> results; + results.begin = index; + results.end = index + 1; + + if (keep(*it)) + results.vector.append(*it); + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) + { + IntermediateResults::value_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(end - begin); + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + reducer.runReduce(reduce, reducedResult, results); + return false; + } + + void finish() + { + reducer.finish(reduce, reducedResult); + } + + inline bool shouldThrottleThread() + { + return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); + } + + inline bool shouldStartThread() + { + return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); + } + + typedef ReducedResultType ReturnType; + typedef ReducedResultType ResultType; + ReducedResultType *result() + { + return &reducedResult; + } +}; + +// Implementation of filter that reports individual results via QFutureInterface +template +class FilteredEachKernel : public IterateKernel::value_type> +{ + typedef typename qValueType::value_type T; + typedef IterateKernel IterateKernelType; + + KeepFunctor keep; + +public: + typedef T ReturnType; + typedef T ResultType; + + FilteredEachKernel(Iterator begin, Iterator end, KeepFunctor _keep) + : IterateKernelType(begin, end), keep(_keep) + { } + + void start() + { + if (this->futureInterface) + this->futureInterface->setFilterMode(true); + IterateKernelType::start(); + } + + bool runIteration(Iterator it, int index, T *) + { + if (keep(*it)) + this->reportResult(&(*it), index); + else + this->reportResult(0, index); + return false; + } + + bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *) + { + const int count = end - begin; + IntermediateResults::value_type> results; + results.begin = begin; + results.end = end; + results.vector.reserve(count); + + Iterator it = sequenceBeginIterator; + advance(it, begin); + for (int i = begin; i < end; ++i) { + if (keep(*it)) + results.vector.append(*it); + advance(it, 1); + } + + this->reportResults(results.vector, begin, count); + return false; + } +}; + +template +inline +ThreadEngineStarter::value_type> +startFiltered(Iterator begin, Iterator end, KeepFunctor functor) +{ + return startThreadEngine(new FilteredEachKernel(begin, end, functor)); +} + +template +inline ThreadEngineStarter +startFiltered(const Sequence &sequence, KeepFunctor functor) +{ + typedef SequenceHolder1, + KeepFunctor> + SequenceHolderType; + return startThreadEngine(new SequenceHolderType(sequence, functor)); +} + +template +inline ThreadEngineStarter startFilteredReduced(const Sequence & sequence, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef typename Sequence::const_iterator Iterator; + typedef ReduceKernel::value_type > Reducer; + typedef FilteredReducedKernel FilteredReduceType; + typedef SequenceHolder2 SequenceHolderType; + return startThreadEngine(new SequenceHolderType(sequence, mapFunctor, reduceFunctor, options)); +} + + +template +inline ThreadEngineStarter startFilteredReduced(Iterator begin, Iterator end, + MapFunctor mapFunctor, ReduceFunctor reduceFunctor, + ReduceOptions options) +{ + typedef ReduceKernel::value_type> Reducer; + typedef FilteredReducedKernel FilteredReduceType; + return startThreadEngine(new FilteredReduceType(begin, end, mapFunctor, reduceFunctor, options)); +} + + +} // namespace QtConcurrent + +#endif // qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentfunctionwrappers.h b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h new file mode 100644 index 0000000000..f31f7d2877 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentfunctionwrappers.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_FUNCTIONWRAPPERS_H +#define QTCONCURRENT_FUNCTIONWRAPPERS_H + +#include + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +template +class FunctionWrapper0 +{ +public: + typedef T (*FunctionPointerType)(); + typedef T result_type; + inline FunctionWrapper0(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()() + { + return functionPointer(); + } +private: + FunctionPointerType functionPointer; +}; + +template +class FunctionWrapper1 +{ +public: + typedef T (*FunctionPointerType)(U u); + typedef T result_type; + inline FunctionWrapper1(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(U u) + { + return functionPointer(u); + } + +private: + FunctionPointerType functionPointer; +}; + +template +class FunctionWrapper2 +{ +public: + typedef T (*FunctionPointerType)(U u, V v); + typedef T result_type; + inline FunctionWrapper2(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(U u, V v) + { + return functionPointer(u, v); + } +private: + FunctionPointerType functionPointer; +}; + +template +class MemberFunctionWrapper +{ +public: + typedef T (C::*FunctionPointerType)(); + typedef T result_type; + inline MemberFunctionWrapper(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(C &c) + { + return (c.*functionPointer)(); + } +private: + FunctionPointerType functionPointer; +}; + +template +class MemberFunctionWrapper1 +{ +public: + typedef T (C::*FunctionPointerType)(U); + typedef T result_type; + + inline MemberFunctionWrapper1(FunctionPointerType _functionPointer) + : functionPointer(_functionPointer) + { } + + inline T operator()(C &c, U u) + { + return (c.*functionPointer)(u); + } + +private: + FunctionPointerType functionPointer; +}; + +template +class ConstMemberFunctionWrapper +{ +public: + typedef T (C::*FunctionPointerType)() const; + typedef T result_type; + inline ConstMemberFunctionWrapper(FunctionPointerType _functionPointer) + :functionPointer(_functionPointer) { } + + inline T operator()(const C &c) const + { + return (c.*functionPointer)(); + } +private: + FunctionPointerType functionPointer; +}; + +} // namespace QtConcurrent. + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp new file mode 100644 index 0000000000..a59e6cfa47 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtconcurrentiteratekernel.h" + +#if defined(Q_OS_MAC) +#include +#include +#include +#elif defined(Q_OS_UNIX) +#if defined(Q_OS_HURD) +#include +#endif +#include +#include +#elif defined(Q_OS_WIN) +#include +#endif + +#include "private/qfunctions_p.h" + + +#ifndef QT_NO_CONCURRENT + +QT_BEGIN_NAMESPACE + +enum { + TargetRatio = 100, + MedianSize = 7 +}; + +#if defined(Q_OS_MAC) + +static qint64 getticks() +{ + return mach_absolute_time(); +} + +#elif defined(Q_OS_UNIX) + + +static qint64 getticks() +{ +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + clockid_t clockId; + +#ifndef _POSIX_THREAD_CPUTIME + clockId = CLOCK_REALTIME; +#elif (_POSIX_THREAD_CPUTIME-0 <= 0) + // if we don't have CLOCK_THREAD_CPUTIME_ID, we have to just use elapsed realtime instead + clockId = CLOCK_REALTIME; + +# if (_POSIX_THREAD_CPUTIME-0 == 0) + // detect availablility of CLOCK_THREAD_CPUTIME_ID + static long useThreadCpuTime = -2; + if (useThreadCpuTime == -2) { + // sysconf() will return either -1 or _POSIX_VERSION (don't care about thread races here) + useThreadCpuTime = sysconf(_SC_THREAD_CPUTIME); + } + if (useThreadCpuTime != -1) + clockId = CLOCK_THREAD_CPUTIME_ID; +# endif +#else + clockId = CLOCK_THREAD_CPUTIME_ID; +#endif + + struct timespec ts; + if (clock_gettime(clockId, &ts) == -1) + return 0; + return (ts.tv_sec * 1000000000) + ts.tv_nsec; +#else + +#ifdef Q_OS_SYMBIAN + return clock(); +#else + // no clock_gettime(), fall back to wall time + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000000) + tv.tv_usec; +#endif + +#endif +} + +#elif defined(Q_OS_WIN) + +static qint64 getticks() +{ + LARGE_INTEGER x; + if (!QueryPerformanceCounter(&x)) + return 0; + return x.QuadPart; +} + +#endif + +static double elapsed(qint64 after, qint64 before) +{ + return double(after - before); +} + +namespace QtConcurrent { + +/*! \internal + +*/ +BlockSizeManager::BlockSizeManager(int iterationCount) +: maxBlockSize(iterationCount / (QThreadPool::globalInstance()->maxThreadCount() * 2)), + beforeUser(0), afterUser(0), + controlPartElapsed(MedianSize), userPartElapsed(MedianSize), + m_blockSize(1) +{ } + +// Records the time before user code. +void BlockSizeManager::timeBeforeUser() +{ + if (blockSizeMaxed()) + return; + + beforeUser = getticks(); + controlPartElapsed.addValue(elapsed(beforeUser, afterUser)); +} + + // Records the time after user code and adjust the block size if we are spending + // to much time in the for control code compared with the user code. +void BlockSizeManager::timeAfterUser() +{ + if (blockSizeMaxed()) + return; + + afterUser = getticks(); + userPartElapsed.addValue(elapsed(afterUser, beforeUser)); + + if (controlPartElapsed.isMedianValid() == false) + return; + + if (controlPartElapsed.median() * TargetRatio < userPartElapsed.median()) + return; + + m_blockSize = qMin(m_blockSize * 2, maxBlockSize); + +#ifdef QTCONCURRENT_FOR_DEBUG + qDebug() << QThread::currentThread() << "adjusting block size" << controlPartElapsed.median() << userPartElapsed.median() << m_blockSize; +#endif + + // Reset the medians after adjusting the block size so we get + // new measurements with the new block size. + controlPartElapsed.reset(); + userPartElapsed.reset(); +} + +int BlockSizeManager::blockSize() +{ + return m_blockSize; +} + +} // namespace QtConcurrent + +QT_END_NAMESPACE + +#endif // QT_NO_CONCURRENT diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.h b/src/corelib/concurrent/qtconcurrentiteratekernel.h new file mode 100644 index 0000000000..186f752e63 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.h @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_ITERATEKERNEL_H +#define QTCONCURRENT_ITERATEKERNEL_H + +#include + +#ifndef QT_NO_CONCURRENT + +#include +#include +#include + +#ifndef QT_NO_STL +# include +#endif + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef qdoc + +namespace QtConcurrent { + +#ifndef QT_NO_STL + using std::advance; +#else + template + void advance(It &it, T value) + { + it+=value; + } +#endif + +/* + The BlockSizeManager class manages how many iterations a thread should + reserve and process at a time. This is done by measuring the time spent + in the user code versus the control part code, and then increasing + the block size if the ratio between them is to small. The block size + management is done on the basis of the median of several timing measuremens, + and it is done induvidualy for each thread. +*/ +class Q_CORE_EXPORT BlockSizeManager +{ +public: + BlockSizeManager(int iterationCount); + void timeBeforeUser(); + void timeAfterUser(); + int blockSize(); +private: + inline bool blockSizeMaxed() + { + return (m_blockSize >= maxBlockSize); + } + + const int maxBlockSize; + qint64 beforeUser; + qint64 afterUser; + Median controlPartElapsed; + Median userPartElapsed; + int m_blockSize; +}; + +template +class ResultReporter +{ +public: + ResultReporter(ThreadEngine *_threadEngine) + :threadEngine(_threadEngine) + { + + } + + void reserveSpace(int resultCount) + { + currentResultCount = resultCount; + vector.resize(qMax(resultCount, vector.count())); + } + + void reportResults(int begin) + { + const int useVectorThreshold = 4; // Tunable parameter. + if (currentResultCount > useVectorThreshold) { + vector.resize(currentResultCount); + threadEngine->reportResults(vector, begin); + } else { + for (int i = 0; i < currentResultCount; ++i) + threadEngine->reportResult(&vector.at(i), begin + i); + } + } + + inline T * getPointer() + { + return vector.data(); + } + + int currentResultCount; + ThreadEngine *threadEngine; + QVector vector; +}; + +template <> +class ResultReporter +{ +public: + inline ResultReporter(ThreadEngine *) { } + inline void reserveSpace(int) { }; + inline void reportResults(int) { }; + inline void * getPointer() { return 0; } +}; + +#ifndef QT_NO_STL +inline bool selectIteration(std::bidirectional_iterator_tag) +{ + return false; // while +} + +inline bool selectIteration(std::forward_iterator_tag) +{ + return false; // while +} + +inline bool selectIteration(std::random_access_iterator_tag) +{ + return true; // for +} +#else +// no stl support, always use while iteration +template +inline bool selectIteration(T) +{ + return false; // while +} +#endif + +template +class IterateKernel : public ThreadEngine +{ +public: + typedef T ResultType; + + IterateKernel(Iterator _begin, Iterator _end) +#if defined (QT_NO_STL) + : begin(_begin), end(_end), current(_begin), currentIndex(0), + forIteration(false), progressReportingEnabled(true) +#else + : begin(_begin), end(_end), current(_begin), currentIndex(0), + forIteration(selectIteration(typename std::iterator_traits::iterator_category())), progressReportingEnabled(true) +#endif + { +#if defined (QT_NO_STL) + iterationCount = 0; +#else + iterationCount = forIteration ? std::distance(_begin, _end) : 0; + +#endif + } + + virtual ~IterateKernel() { } + + virtual bool runIteration(Iterator it, int index , T *result) + { Q_UNUSED(it); Q_UNUSED(index); Q_UNUSED(result); return false; } + virtual bool runIterations(Iterator _begin, int beginIndex, int endIndex, T *results) + { Q_UNUSED(_begin); Q_UNUSED(beginIndex); Q_UNUSED(endIndex); Q_UNUSED(results); return false; } + + void start() + { + progressReportingEnabled = this->isProgressReportingEnabled(); + if (progressReportingEnabled && iterationCount > 0) + this->setProgressRange(0, iterationCount); + } + + bool shouldStartThread() + { + if (forIteration) + return (currentIndex < iterationCount) && !this->shouldThrottleThread(); + else // whileIteration + return (iteratorThreads == 0); + } + + ThreadFunctionResult threadFunction() + { + if (forIteration) + return this->forThreadFunction(); + else // whileIteration + return this->whileThreadFunction(); + } + + ThreadFunctionResult forThreadFunction() + { + BlockSizeManager blockSizeManager(iterationCount); + ResultReporter resultReporter(this); + + for(;;) { + if (this->isCanceled()) + break; + + const int currentBlockSize = blockSizeManager.blockSize(); + + if (currentIndex >= iterationCount) + break; + + // Atomically reserve a block of iterationCount for this thread. + const int beginIndex = currentIndex.fetchAndAddRelease(currentBlockSize); + const int endIndex = qMin(beginIndex + currentBlockSize, iterationCount); + + if (beginIndex >= endIndex) { + // No more work + break; + } + + this->waitForResume(); // (only waits if the qfuture is paused.) + + if (shouldStartThread()) + this->startThread(); + + const int finalBlockSize = endIndex - beginIndex; // block size adjusted for possible end-of-range + resultReporter.reserveSpace(finalBlockSize); + + // Call user code with the current iteration range. + blockSizeManager.timeBeforeUser(); + const bool resultsAvailable = this->runIterations(begin, beginIndex, endIndex, resultReporter.getPointer()); + blockSizeManager.timeAfterUser(); + + if (resultsAvailable) + resultReporter.reportResults(beginIndex); + + // Report progress if progress reporting enabled. + if (progressReportingEnabled) { + completed.fetchAndAddAcquire(finalBlockSize); + this->setProgressValue(this->completed); + } + + if (this->shouldThrottleThread()) + return ThrottleThread; + } + return ThreadFinished; + } + + ThreadFunctionResult whileThreadFunction() + { + if (iteratorThreads.testAndSetAcquire(0, 1) == false) + return ThreadFinished; + + ResultReporter resultReporter(this); + resultReporter.reserveSpace(1); + + while (current != end) { + // The following two lines breaks support for input iterators according to + // the sgi docs: dereferencing prev after calling ++current is not allowed + // on input iterators. (prev is dereferenced inside user.runIteration()) + Iterator prev = current; + ++current; + int index = currentIndex.fetchAndAddRelaxed(1); + iteratorThreads.testAndSetRelease(1, 0); + + this->waitForResume(); // (only waits if the qfuture is paused.) + + if (shouldStartThread()) + this->startThread(); + + const bool resultAavailable = this->runIteration(prev, index, resultReporter.getPointer()); + if (resultAavailable) + resultReporter.reportResults(index); + + if (this->shouldThrottleThread()) + return ThrottleThread; + + if (iteratorThreads.testAndSetAcquire(0, 1) == false) + return ThreadFinished; + } + + return ThreadFinished; + } + + +public: + const Iterator begin; + const Iterator end; + Iterator current; + QAtomicInt currentIndex; + bool forIteration; + QAtomicInt iteratorThreads; + int iterationCount; + + bool progressReportingEnabled; + QAtomicInt completed; +}; + +} // namespace QtConcurrent + +#endif //qdoc + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QT_NO_CONCURRENT + +#endif diff --git a/src/corelib/concurrent/qtconcurrentmap.cpp b/src/corelib/concurrent/qtconcurrentmap.cpp new file mode 100644 index 0000000000..fe083f17a2 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmap.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \namespace QtConcurrent + \inmodule QtCore + \since 4.4 + \brief The QtConcurrent namespace provides high-level APIs that make it + possible to write multi-threaded programs without using low-level + threading primitives. + + See the \l {Concurrent Programming}{Qt Concurrent} chapter in + the \l{threads.html}{threading} documentation. + + \inheaderfile QtCore + \ingroup thread +*/ + +/*! + \namespace QtConcurrent::internal + \internal + + \brief The QtConcurrent::internal namespace contains QtConcurrent + implementation details. +*/ + +/*! + \enum QtConcurrent::ReduceOption + This enum specifies the order of which results from the map or filter + function are passed to the reduce function. + + \value UnorderedReduce Reduction is done in an arbitrary order. + \value OrderedReduce Reduction is done in the order of the + original sequence. + \value SequentialReduce Reduction is done sequentially: only one + thread will enter the reduce function at a time. (Parallel reduction + might be supported in a future version of Qt Concurrent.) +*/ + +/*! + \headerfile + \title Concurrent Map and Map-Reduce + \ingroup thread + + \brief The header provides concurrent Map and MapReduce. + + These functions are a part of the \l {Concurrent Programming}{Qt Concurrent} framework. + + The QtConcurrent::map(), QtConcurrent::mapped() and + QtConcurrent::mappedReduced() functions run computations in parallel on + the items in a sequence such as a QList or a QVector. QtConcurrent::map() + modifies a sequence in-place, QtConcurrent::mapped() returns a new + sequence containing the modified content, and QtConcurrent::mappedReduced() + returns a single result. + + Each of the above functions has a blocking variant that returns + the final result instead of a QFuture. You use them in the same + way as the asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 7 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QList and QImage). + + \section1 Concurrent Map + + QtConcurrent::mapped() takes an input sequence and a map function. This map + function is then called for each item in the sequence, and a new sequence + containing the return values from the map function is returned. + + The map function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 0 + + T and U can be any type (and they can even be the same type), but T must + match the type stored in the sequence. The function returns the modified + or \e mapped content. + + This example shows how to apply a scale function to all the items + in a sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 1 + + The results of the map are made available through QFuture. See the + QFuture and QFutureWatcher documentation for more information on how to + use QFuture in your applications. + + If you want to modify a sequence in-place, use QtConcurrent::map(). The + map function must then be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 2 + + Note that the return value and return type of the map function are not + used. + + Using QtConcurrent::map() is similar to using QtConcurrent::mapped(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 3 + + Since the sequence is modified in place, QtConcurrent::map() does not + return any results via QFuture. However, you can still use QFuture and + QFutureWatcher to monitor the status of the map. + + \section1 Concurrent Map-Reduce + + QtConcurrent::mappedReduced() is similar to QtConcurrent::mapped(), but + instead of returning a sequence with the new results, the results are + combined into a single value using a reduce function. + + The reduce function must be of the form: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 4 + + T is the type of the final result, U is the return type of the map + function. Note that the return value and return type of the reduce + function are not used. + + Call QtConcurrent::mappedReduced() like this: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 5 + + The reduce function will be called once for each result returned by the map + function, and should merge the \e{intermediate} into the \e{result} + variable. QtConcurrent::mappedReduced() guarantees that only one thread + will call reduce at a time, so using a mutex to lock the result variable + is not necessary. The QtConcurrent::ReduceOptions enum provides a way to + control the order in which the reduction is done. If + QtConcurrent::UnorderedReduce is used (the default), the order is + undefined, while QtConcurrent::OrderedReduce ensures that the reduction + is done in the order of the original sequence. + + \section1 Additional API Features + + \section2 Using Iterators instead of Sequence + + Each of the above functions has a variant that takes an iterator range + instead of a sequence. You use them in the same way as the sequence + variants: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 6 + + \section2 Blocking Variants + + Each of the above functions has a blocking variant that returns + the final result instead of a QFuture. You use them in the same + way as the asynchronous variants. + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 7 + + Note that the result types above are not QFuture objects, but real result + types (in this case, QList and QImage). + + \section2 Using Member Functions + + QtConcurrent::map(), QtConcurrent::mapped(), and + QtConcurrent::mappedReduced() accept pointers to member functions. + The member function class type must match the type stored in the sequence: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 8 + + Note that when using QtConcurrent::mappedReduced(), you can mix the use of + normal and member functions freely: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 9 + + \section2 Using Function Objects + + QtConcurrent::map(), QtConcurrent::mapped(), and + QtConcurrent::mappedReduced() accept function objects, which can be used to + add state to a function call. The result_type typedef must define the + result type of the function call operator: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 14 + + \section2 Using Bound Function Arguments + + Note that Qt does not provide support for bound functions. This is + provided by 3rd party libraries like + \l{http://www.boost.org/libs/bind/bind.html}{Boost} or + \l{http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf}{C++ + TR1 Library Extensions}. + + If you want to use a map function that takes more than one argument you can + use boost::bind() or std::tr1::bind() to transform it onto a function that + takes one argument. + + As an example, we'll use QImage::scaledToWidth(): + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 10 + + scaledToWidth takes three arguments (including the "this" pointer) and + can't be used with QtConcurrent::mapped() directly, because + QtConcurrent::mapped() expects a function that takes one argument. To use + QImage::scaledToWidth() with QtConcurrent::mapped() we have to provide a + value for the \e{width} and the \e{transformation mode}: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 11 + + The return value from boost::bind() is a function object (functor) with + the following signature: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 12 + + This matches what QtConcurrent::mapped() expects, and the complete example + becomes: + + \snippet doc/src/snippets/code/src_corelib_concurrent_qtconcurrentmap.cpp 13 +*/ + +/*! + \fn QFuture QtConcurrent::map(Sequence &sequence, MapFunction function) + \relates + + Calls \a function once for each item in \a sequence. The \a function is + passed a reference to the item, so that any modifications done to the item + will appear in \a sequence. +*/ + +/*! + \fn QFuture QtConcurrent::map(Iterator begin, Iterator end, MapFunction function) + \relates + + Calls \a function once for each item from \a begin to \a end. The + \a function is passed a reference to the item, so that any modifications + done to the item will appear in the sequence which the iterators belong to. +*/ + +/*! + \fn QFuture QtConcurrent::mapped(const Sequence &sequence, MapFunction function) + \relates + + Calls \a function once for each item in \a sequence and returns a future + with each mapped item as a result. You can use QFuture::const_iterator or + QFutureIterator to iterate through the results. +*/ + +/*! + \fn QFuture QtConcurrent::mapped(ConstIterator begin, ConstIterator end, MapFunction function) + \relates + + Calls \a function once for each item from \a begin to \a end and returns a + future with each mapped item as a result. You can use + QFuture::const_iterator or QFutureIterator to iterate through the results. +*/ + +/*! + \fn QFuture QtConcurrent::mappedReduced(const Sequence &sequence, + MapFunction mapFunction, ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions) + + \relates + + Calls \a mapFunction once for each item in \a sequence. The return value of + each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is determined by \a reduceOptions. +*/ + +/*! + \fn QFuture QtConcurrent::mappedReduced(ConstIterator begin, + ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, + QtConcurrent::ReduceOptions reduceOptions) + + \relates + + Calls \a mapFunction once for each item from \a begin to \a end. The return + value of each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. By default, the order in which + \a reduceFunction is called is undefined. + + \note QtConcurrent::OrderedReduce results in the ordered reduction. +*/ + +/*! + \fn void QtConcurrent::blockingMap(Sequence &sequence, MapFunction function) + + Calls \a function once for each item in \a sequence. The \a function is + passed a reference to the item, so that any modifications done to the item + will appear in \a sequence. + + \note This function will block until all items in the sequence have been processed. + + \sa map() +*/ + +/*! + \fn void QtConcurrent::blockingMap(Iterator begin, Iterator end, MapFunction function) + + Calls \a function once for each item from \a begin to \a end. The + \a function is passed a reference to the item, so that any modifications + done to the item will appear in the sequence which the iterators belong to. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa map() +*/ + +/*! + \fn T QtConcurrent::blockingMapped(const Sequence &sequence, MapFunction function) + + Calls \a function once for each item in \a sequence and returns a Sequence containing + the results. The type of the results will match the type returned my the MapFunction. + + \note This function will block until all items in the sequence have been processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function) + + Calls \a function once for each item from \a begin to \a end and returns a + container with the results. Specify the type of container as the a template + argument, like this: + + \code + QList ints = QtConcurrent::blockingMapped >(beginIterator, endIterator, fn); + \endcode + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMappedReduced(const Sequence &sequence, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + \relates + + Calls \a mapFunction once for each item in \a sequence. The return value of + each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is determined by \a reduceOptions. + + \note This function will block until all items in the sequence have been processed. + + \sa mapped() +*/ + +/*! + \fn T QtConcurrent::blockingMappedReduced(ConstIterator begin, ConstIterator end, MapFunction mapFunction, ReduceFunction reduceFunction, QtConcurrent::ReduceOptions reduceOptions) + + \relates + + Calls \a mapFunction once for each item from \a begin to \a end. The return + value of each \a mapFunction is passed to \a reduceFunction. + + Note that while \a mapFunction is called concurrently, only one thread at a + time will call \a reduceFunction. The order in which \a reduceFunction is + called is undefined. + + \note This function will block until the iterator reaches the end of the + sequence being processed. + + \sa blockingMappedReduced() +*/ diff --git a/src/corelib/concurrent/qtconcurrentmap.h b/src/corelib/concurrent/qtconcurrentmap.h new file mode 100644 index 0000000000..80edf7e136 --- /dev/null +++ b/src/corelib/concurrent/qtconcurrentmap.h @@ -0,0 +1,780 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTCONCURRENT_MAP_H +#define QTCONCURRENT_MAP_H + +#include + +#ifndef QT_NO_CONCURRENT + +#include +#include +#include +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifdef qdoc + +namespace QtConcurrent { + + QFuture map(Sequence &sequence, MapFunction function); + QFuture map(Iterator begin, Iterator end, MapFunction function); + + template + QFuture mapped(const Sequence &sequence, MapFunction function); + template + QFuture mapped(ConstIterator begin, ConstIterator end, MapFunction function); + + template + QFuture mappedReduced(const Sequence &sequence, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + template + QFuture mappedReduced(ConstIterator begin, + ConstIterator end, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + + void blockingMap(Sequence &sequence, MapFunction function); + void blockingMap(Iterator begin, Iterator end, MapFunction function); + + template + T blockingMapped(const Sequence &sequence, MapFunction function); + template + T blockingMapped(ConstIterator begin, ConstIterator end, MapFunction function); + + template + T blockingMappedReduced(const Sequence &sequence, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + template + T blockingMappedReduced(ConstIterator begin, + ConstIterator end, + MapFunction function, + ReduceFunction function, + QtConcurrent::ReduceOptions options = UnorderedReduce | SequentialReduce); + +} // namespace QtConcurrent + +#else + +namespace QtConcurrent { + +// map() on sequences +template +QFuture map(Sequence &sequence, MapFunctor map) +{ + return startMap(sequence.begin(), sequence.end(), map); +} + +template +QFuture map(Sequence &sequence, T (map)(U)) +{ + return startMap(sequence.begin(), sequence.end(), FunctionWrapper1(map)); +} + +template +QFuture map(Sequence &sequence, T (C::*map)()) +{ + return startMap(sequence.begin(), sequence.end(), MemberFunctionWrapper(map)); +} + +// map() on iterators +template +QFuture map(Iterator begin, Iterator end, MapFunctor map) +{ + return startMap(begin, end, map); +} + +template +QFuture map(Iterator begin, Iterator end, T (map)(U)) +{ + return startMap(begin, end, FunctionWrapper1(map)); +} + +template +QFuture map(Iterator begin, Iterator end, T (C::*map)()) +{ + return startMap(begin, end, MemberFunctionWrapper(map)); +} + +// mappedReduced() for sequences. +template +QFuture mappedReduced(const Sequence &sequence, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, map, reduce, options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + MapFunctor map, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, map, FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + MapFunctor map, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, map, MemberFunctionWrapper1(reduce), options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (map)(U), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, FunctionWrapper1(map), reduce, options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (C::*map)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, ConstMemberFunctionWrapper(map), reduce, options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (map)(U), + V (reduce)(W &, X), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (sequence, FunctionWrapper1(map), FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced (sequence, ConstMemberFunctionWrapper(map), + FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (map)(U), + V (C::*reduce)(W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced (sequence, FunctionWrapper1(map), + MemberFunctionWrapper1(reduce), options); +} + +template +QFuture mappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (D::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced(sequence, ConstMemberFunctionWrapper(map), + MemberFunctionWrapper1(reduce), options); +} + +// mappedReduced() for iterators +template +QFuture mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, map, reduce, options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (reduce)(U &, V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, map, FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (C::*reduce)(U), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, map, MemberFunctionWrapper1(reduce), options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, FunctionWrapper1(map), reduce, options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, ConstMemberFunctionWrapper(map), reduce, options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (reduce)(W &, X), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, FunctionWrapper1(map), FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (reduce)(V &, W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced(begin, end, ConstMemberFunctionWrapper(map), + FunctionWrapper2(reduce), options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (C::*reduce)(W), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced + (begin, end, FunctionWrapper1(map), MemberFunctionWrapper1(reduce), options); +} + +template +QFuture mappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (D::*reduce)(V), + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return startMappedReduced(begin, end, ConstMemberFunctionWrapper(map), + MemberFunctionWrapper1(reduce), options); +} + +// mapped() for sequences +template +QFuture mapped(const Sequence &sequence, MapFunctor map) +{ + return startMapped(sequence, map); +} + +template +QFuture mapped(const Sequence &sequence, T (map)(U)) +{ + return startMapped(sequence, FunctionWrapper1(map)); +} + +template +QFuture mapped(const Sequence &sequence, T (C::*map)() const) +{ + return startMapped(sequence, ConstMemberFunctionWrapper(map)); +} + +// mapped() for iterator ranges. +template +QFuture mapped(Iterator begin, Iterator end, MapFunctor map) +{ + return startMapped(begin, end, map); +} + +template +QFuture mapped(Iterator begin, Iterator end, T (map)(U)) +{ + return startMapped(begin, end, FunctionWrapper1(map)); +} + +template +QFuture mapped(Iterator begin, Iterator end, T (C::*map)() const) +{ + return startMapped(begin, end, ConstMemberFunctionWrapper(map)); +} + + +template +void blockingMap(Sequence &sequence, MapFunctor map) +{ + startMap(sequence.begin(), sequence.end(), map).startBlocking(); +} + +template +void blockingMap(Sequence &sequence, T (map)(U)) +{ + startMap(sequence.begin(), sequence.end(), QtConcurrent::FunctionWrapper1(map)).startBlocking(); +} + +template +void blockingMap(Sequence &sequence, T (C::*map)()) +{ + startMap(sequence.begin(), sequence.end(), QtConcurrent::MemberFunctionWrapper(map)).startBlocking(); +} + +template +void blockingMap(Iterator begin, Iterator end, MapFunctor map) +{ + startMap(begin, end, map).startBlocking(); +} + +template +void blockingMap(Iterator begin, Iterator end, T (map)(U)) +{ + startMap(begin, end, QtConcurrent::FunctionWrapper1(map)).startBlocking(); +} + +template +void blockingMap(Iterator begin, Iterator end, T (C::*map)()) +{ + startMap(begin, end, QtConcurrent::MemberFunctionWrapper(map)).startBlocking(); +} + +template +ResultType blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + ReduceFunctor reduce, + ReduceOptions options = ReduceOptions(UnorderedReduce | SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, map, reduce, options).startBlocking(); +} + +template +U blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + T (reduce)(U &, V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + map, + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +C blockingMappedReduced(const Sequence &sequence, + MapFunctor map, + T (C::*reduce)(U), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + map, + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +template +ResultType blockingMappedReduced(const Sequence &sequence, + T (map)(U), + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::FunctionWrapper1(map), + reduce, + options) + .startBlocking(); +} + +template +ResultType blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::ConstMemberFunctionWrapper(map), + reduce, + options) + .startBlocking(); +} + +template +W blockingMappedReduced(const Sequence &sequence, + T (map)(U), + V (reduce)(W &, X), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::FunctionWrapper1(map), + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +V blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (reduce)(V &, W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::ConstMemberFunctionWrapper(map), + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +C blockingMappedReduced(const Sequence &sequence, + T (map)(U), + V (C::*reduce)(W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::FunctionWrapper1(map), + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +template +D blockingMappedReduced(const Sequence &sequence, + T (C::*map)() const, + U (D::*reduce)(V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (sequence, + QtConcurrent::ConstMemberFunctionWrapper(map), + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +template +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, end, map, reduce, options).startBlocking(); +} + +template +U blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (reduce)(U &, V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + map, + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +C blockingMappedReduced(Iterator begin, + Iterator end, + MapFunctor map, + T (C::*reduce)(U), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + map, + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +template +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::FunctionWrapper1(map), + reduce, + options) + .startBlocking(); +} + +template +ResultType blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + ReduceFunctor reduce, + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper(map), + reduce, + options) + .startBlocking(); +} + +template +W blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (reduce)(W &, X), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::FunctionWrapper1(map), + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +V blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (reduce)(V &, W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper(map), + QtConcurrent::FunctionWrapper2(reduce), + options) + .startBlocking(); +} + +template +C blockingMappedReduced(Iterator begin, + Iterator end, + T (map)(U), + V (C::*reduce)(W), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::FunctionWrapper1(map), + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +template +D blockingMappedReduced(Iterator begin, + Iterator end, + T (C::*map)() const, + U (D::*reduce)(V), + QtConcurrent::ReduceOptions options = QtConcurrent::ReduceOptions(QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce)) +{ + return QtConcurrent::startMappedReduced + (begin, + end, + QtConcurrent::ConstMemberFunctionWrapper(map), + QtConcurrent::MemberFunctionWrapper1(reduce), + options) + .startBlocking(); +} + +// mapped() for sequences with a different putput sequence type. +template +OutputSequence blockingMapped(const InputSequence &sequence, MapFunctor map) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template +OutputSequence blockingMapped(const InputSequence &sequence, T (map)(U)) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} + +template +OutputSequence blockingMapped(const InputSequence &sequence, T (C::*map)() const) +{ + return blockingMappedReduced(sequence, map, &OutputSequence::push_back, + QtConcurrent::OrderedReduce); +} +#ifndef QT_NO_TEMPLATE_TEMPLATE_PARAMETERS + +// overloads for changing the container value type: +template