Merge "Merge remote branch 'gerrit/master' into refactor" into refactor

This commit is contained in:
Jørgen Lind 2011-08-04 09:14:17 +02:00 committed by Qt by Nokia
commit 673160b9fd
133 changed files with 2917 additions and 1259 deletions

340
bin/qtmodule-configtests Executable file
View File

@ -0,0 +1,340 @@
#!/usr/bin/perl
######################################################################
#
# Runs any module configuration tests
#
# Called (currently) from syncqt, and expects a few arguments
#
# configtests $basedir $out_basedir $qtbasedir $quietmode
#
# Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
# Contact: Nokia Corporation (qt-info@nokia.com)
#
######################################################################
use strict;
use warnings;
# use packages -------------------------------------------------------
use File::Basename;
use File::Path 'mkpath';
use File::Spec::Functions;
use Cwd;
use Cwd 'abs_path';
use Config;
# Which file to look for the %configtests variable in
my $configTestSource = "sync.profile";
if ($#ARGV < 3) {
warn "Usage:\n";
warn " $0 <module base directory> <module output directory> <QtBase directory> <generator spec>\n";
exit 1;
}
# These might be needed in sync.profile
our $basedir = $ARGV[0];
our $out_basedir = $ARGV[1];
our $qtbasedir = $ARGV[2];
my $generator = $ARGV[3];
our %configtests;
my $qmakeCachePath = catfile($out_basedir, ".qmake.cache");
my $QMAKE = catfile($qtbasedir, "bin", ($^O =~ /win32/i) ? 'qmake.exe' : 'qmake');
if (!-x $QMAKE) {
# try the qmake from the path (e.g. this is a shadow build)
$QMAKE = 'qmake';
}
# Need to use the right make
# SYMBIAN_UNIX/MINGW should fall back to the non SYMBIAN ones
my $MAKE = 'make'; # default, only works on unix
if ($generator =~ /UNIX|XCODE/i) { # XCODE = make?
$MAKE = 'make';
} elsif ($generator =~ /MINGW/i) {
$MAKE = 'mingw32-make';
} elsif ($generator =~ /MSVC.NET|MSBUILD/i) {
$MAKE = 'nmake';
} else {
# Unhandled (at least): BMAKE, GBUILD, SYMBIAN_ABLD, SYMBIAN_SBSV2
warn "Unrecognized generator spec ($generator) - assuming '$MAKE'\n";
}
######################################################################
# Syntax: fileContents(filename)
# Params: filename, string, filename of file to return contents
#
# Purpose: Get the contents of a file.
# Returns: String with contents of the file, or empty string if file
# doens't exist.
# Warning: Dies if it does exist but script cannot get read access.
######################################################################
sub fileContents {
my ($filename) = @_;
my $filecontents = "";
if (-e $filename) {
open(I, "< $filename") || die "Could not open $filename for reading, read block?";
local $/;
binmode I;
$filecontents = <I>;
close I;
}
return $filecontents;
}
######################################################################
# Syntax: loadConfigTests()
#
# Purpose: Loads the config tests from the source basedir into %configtests.
# Returns: Nothing
######################################################################
sub loadConfigTests {
my $configprofile = catfile($basedir, $configTestSource);
my $result;
unless ($result = do $configprofile) {
die "configtests couldn't parse $configprofile: $@\n" if $@;
# We don't check for non null output, since that is valid
}
}
######################################################################
# Syntax: hashesAreDifferent
#
# Purpose: Compares two hashes. (must have same key=value for everything)
# Returns: 0 if they are the same, 1 otherwise
######################################################################
sub hashesAreDifferent {
my %a = %{$_[0]};
my %b = %{$_[1]};
if (keys %a != keys %b) {
return 1;
}
my %cmp = map { $_ => 1 } keys %a;
for my $key (keys %b) {
last unless exists $cmp{$key};
last unless $a{$key} eq $b{$key};
delete $cmp{$key};
}
if (%cmp) {
return 1;
} else {
return 0;
}
}
######################################################################
# Syntax: executeSomething
# Params: A list of things.
#
# Purpose: Executes the first arg, passing the list.
# stderr is redirected to stdout, and the output is captured.
# Returns: The output.
######################################################################
sub executeSomething {
my ($program, @args) = @_;
my $pid = open(KID_TO_READ, "-|");
my $output;
if ($pid) { # parent
while (<KID_TO_READ>) {
$output = $output . $_;
}
close(KID_TO_READ) || $! == 0 || warn "\nFailed to execute $program: exited $?";
} else {
# redirect STDERR to STDOUT
open STDERR, ">&STDOUT";
# Exec something
exec ($program, @args) || die "\nCan't exec $program: $!\n";
# NOTREACHED
}
return $output;
}
######################################################################
# Syntax: executeTest()
# Params: testName
#
# The testName variable controls the actual config test run - the
# source is assumed to be in $basedir/config.tests/$testName, and
# when 'qmake; make clean; make' is run, is expected to produce a file
# $out_basedir/config.tests/$testName/$testName. If this test passes,
# then 'config_test_$testName = yes' will be written to $out_basedir/.qmake.cache
#
# Purpose: Runs a configuration time test.
# Returns: 0 if the test fails, 1 if it passes, 2 if the test is skipped
# (e.g. .pro file has requires(x) and x is not satisfied)
######################################################################
sub executeTest {
my ($testName) = @_;
my $oldWorkingDir = getcwd();
my $ret = 0;
my @QMAKEARGS = ('CONFIG-=debug_and_release');
my $testOutDir = catdir($out_basedir, 'config.tests', $testName);
# Since we might be cross compiling, look for barename (Linux) and .exe (Win32/Symbian)
my $testOutFile1 = catfile($testOutDir, "$testName.exe");
my $testOutFile2 = catfile($testOutDir, $testName);
if (abs_path($basedir) eq abs_path($out_basedir)) {
chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n";
} else { # shadow build
if (! -e $testOutDir) {
mkpath $testOutDir or die "\nUnable to create shadow build config test directory ($testOutDir): $!\n";
}
chdir $testOutDir or die "\nUnable to change to config test directory ($testOutDir): $!\n";
push (@QMAKEARGS, catdir($basedir, 'config.tests', $testName));
}
# First remove existing stuff (XXX this probably needs generator specific code, but hopefully
# the target removal below will suffice)
if (-e "Makefile") {
executeSomething($MAKE, 'distclean');
}
# and any targets that we might find that weren't distcleaned
unlink $testOutFile1, $testOutFile2;
# Run qmake && make
executeSomething($QMAKE, @QMAKEARGS);
my $makeOutput = executeSomething(($MAKE));
# If make prints "blah blah blah\nSkipped." we consider this a skipped test
if ($makeOutput !~ qr(^Skipped\.$)ms) {
# Check the test exists (can't reliably execute, especially for cross compilation)
if (-e $testOutFile1 or -e $testOutFile2) {
$ret = 1;
}
} else {
$ret = 2;
}
chdir $oldWorkingDir or die "\nUnable to restore working directory: $!\n";
return $ret;
}
# Now run configuration tests
# %configtests is a map from config test name to a map of parameters
# e.g:
#
# %configtests = (
# "simple" => {fatal => 1, message => "Missing required 'simple' component\n"},
# "failed" => {message => "You need to install the FAILED sdk for this to work\n"}
# );
#
# Parameters and their defaults:
# - fatal [false] - whether failing this test should abort everything
# - message [""] - A special message to display if this test fails
#
loadConfigTests();
# Only do this step for modules that have config tests
# (qtbase doesn't). We try to preserve existing contents (and furthermore
# only write to .qmake.cache if the tests change)
if (abs_path($out_basedir) ne abs_path($qtbasedir)) {
# Read any existing content
my $existingContents = fileContents($qmakeCachePath);
my %oldTestResults;
my %newTestResults;
my @fatalTestsEncountered;
# Parse the existing results so we can check if we change them
while ($existingContents =~ /^config_test_(.*) = (yes|no)$/gm) {
$oldTestResults{$1} = $2;
}
# Get the longest length test name so we can pretty print
use List::Util qw(max);
my $maxNameLength = max map { length $_ } keys %configtests;
# Turn off buffering
$| = 1;
# Now run the configuration tests
print "Configuration tests:\n";
while ((my $testName, my $testParameters) = each %configtests) {
printf " % *s: ", $maxNameLength, $testName; # right aligned, yes/no lines up
my $fatalTest = $testParameters->{"fatal"} // 0;
my $message = $testParameters->{"message"};
my $testResult = executeTest($testName);
my @testResultStrings = ("no\n","yes\n","skipped\n");
$newTestResults{$testName} = (($testResult == 1) ? "yes" : "no"); # skipped = no
if ($testResult == 0) {
# Failed test
if ($fatalTest) {
print "no (fatal)\n";
# Report the fatality at the end, too
push (@fatalTestsEncountered, $testName);
} else {
print "no\n";
}
if (defined($message)) {
print $message;
print "\n" unless chop $message eq "\n";
}
} else {
# yes or skipped
print $testResultStrings[$testResult];
}
}
# Check if the test results are different
if (hashesAreDifferent(\%oldTestResults, \%newTestResults)) {
# Generate the new contents
my $newContents = $existingContents;
# Strip out any existing config test results
$newContents =~ s/^config_test_.*$//gms;
$newContents =~ s/^# Compile time test results.*$//gms;
# Add any remaining content and make sure we start on a new line
if ($newContents and chop $newContents ne '\n') {
$newContents = $newContents . "\n";
}
# Results and header
if (%newTestResults) {
$newContents = $newContents . '# Compile time test results ('.(localtime).")\n";
# Results
while ((my $testName, my $testResult) = each %newTestResults) {
$newContents = $newContents . "config_test_$testName = $testResult\n";
}
}
# and open the file
open my $cacheFileHandle, ">$qmakeCachePath" or die "Unable to open $qmakeCachePath for writing: $!\n";
print $cacheFileHandle $newContents;
close $cacheFileHandle or die "Unable to close $qmakeCachePath: $!\n";
}
# Now see if we have to die
if (@fatalTestsEncountered) {
if ($#fatalTestsEncountered == 0) {
warn "Mandatory configuration test (".$fatalTestsEncountered[0].") failed.\n\n";
} else {
warn "Mandatory configuration tests (". join (", ", @fatalTestsEncountered) . ") failed.\n\n";
}
exit -1;
}
}
exit 0;

View File

@ -15,6 +15,7 @@ use Cwd;
use Cwd 'abs_path';
use Config;
use strict;
use English qw(-no_match_vars );
# set output basedir to be where ever syncqt is run from
our $out_basedir = getcwd();
@ -38,7 +39,7 @@ our (%modules, %moduleheaders, %classnames, %mastercontent, %modulepris);
my $isunix = 0;
my $module = 0;
my $showonly = 0;
my $quiet = 0;
my $verbose_level = 1;
my $remove_stale = 1;
my $force_win = 0;
my $force_relative = 0;
@ -50,6 +51,7 @@ my $module_fwd = "";
my $cache_module_fwd = 0;
my $developer_build = 0;
my $no_module_version_header = 0;
my $makefile_generator = "";
my @modules_to_sync ;
$force_relative = 1 if ( -d "/System/Library/Frameworks" );
@ -75,7 +77,9 @@ sub showUsage
print " -showonly Show action but not perform (default: " . ($showonly ? "yes" : "no") . ")\n";
print " -outdir <PATH> Specify output directory for sync (default: $out_basedir)\n";
print " -qtdir <PATH> Set the path to QtBase (detected: " . (defined $qtbasedir ? $qtbasedir : "-none-") . ")\n";
print " -quiet Only report problems, not activity (default: " . ($quiet ? "yes" : "no") . ")\n";
print " -quiet Only report problems, not activity (same as -verbose 0)\n";
print " -v, -verbose <level> Sets the verbosity level (max. 4) (default: $verbose_level)\n";
print " The short form increases the level by +1\n";
print " -separate-module <NAME>:<PROFILEDIR>:<HEADERDIR>\n";
print " Create headers for <NAME> with original headers in\n";
print " <HEADERDIR> relative to <PROFILEDIR> \n";
@ -88,6 +92,7 @@ sub showUsage
print " easy development\n";
print " -no-module-version-header\n";
print " Don't create module version header file\n";
print " -generator <PATH> Specify the makefile generator setting (e.g. 'UNIX')\n";
print " -help This help\n";
exit 0;
}
@ -273,6 +278,15 @@ sub classNames {
return @ret;
}
sub make_path {
my ($dir, $lib, $be_verbose) = @_;
unless(-e $dir) {
mkpath $dir;
$dir = "<outbase>" . substr($dir, length($out_basedir)) if ($be_verbose < 3);
print "$lib: mkpath $dir\n" if ($be_verbose > 1);
}
}
######################################################################
# Syntax: syncHeader(header, iheader, copy, timestamp)
# Params: header, string, filename to create "symlink" for
@ -284,14 +298,14 @@ sub classNames {
# Returns: 1 if successful, else 0.
######################################################################
sub syncHeader {
my ($header, $iheader, $copy, $ts) = @_;
my ($lib, $header, $iheader, $copy, $ts) = @_;
$iheader =~ s=\\=/=g;
$header =~ s=\\=/=g;
return copyFile($iheader, $header) if($copy);
return copyFile($lib, $iheader, $header) if($copy);
unless(-e $header) {
my $header_dir = dirname($header);
mkpath $header_dir, !$quiet;
make_path($header_dir, $lib, $verbose_level);
#write it
my $iheader_out = fixPaths($iheader, $header_dir);
@ -412,7 +426,7 @@ sub fileCompare {
######################################################################
sub copyFile
{
my ($file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_;
my ($lib, $file,$ifile, $copy,$knowdiff,$filecontents,$ifilecontents) = @_;
# Bi-directional synchronization
open( I, "< " . $file ) || die "Could not open $file for reading";
local $/;
@ -434,7 +448,7 @@ sub copyFile
if ( $knowdiff || ($filecontents ne $ifilecontents) ) {
if ( $copy > 0 ) {
my $file_dir = dirname($file);
mkpath $file_dir, !$quiet unless(-e $file_dir);
make_path($file_dir, $lib, $verbose_level);
open(O, "> " . $file) || die "Could not open $file for writing (no write permission?)";
local $/;
binmode O;
@ -444,7 +458,7 @@ sub copyFile
return 1;
} elsif ( $copy < 0 ) {
my $ifile_dir = dirname($ifile);
mkpath $ifile_dir, !$quiet unless(-e $ifile_dir);
make_path($ifile_dir, $lib, $verbose_level);
open(O, "> " . $ifile) || die "Could not open $ifile for writing (no write permission?)";
local $/;
binmode O;
@ -468,10 +482,10 @@ sub copyFile
######################################################################
sub symlinkFile
{
my ($file,$ifile) = @_;
my ($lib, $file, $ifile) = @_;
if ($isunix) {
print "symlink created for $file " unless $quiet;
print "$lib: symlink created for $file " if ($verbose_level);
if ( $force_relative && ($ifile =~ /^$quoted_basedir/)) {
my $t = getcwd();
my $c = -1;
@ -479,12 +493,12 @@ sub symlinkFile
$t =~ s-^$quoted_basedir/--;
$p .= "../" while( ($c = index( $t, "/", $c + 1)) != -1 );
$file =~ s-^$quoted_basedir/-$p-;
print " ($file)\n" unless $quiet;
print " ($file)\n" if($verbose_level);
}
print "\n" unless $quiet;
print "\n" if($verbose_level);
return symlink($file, $ifile);
}
return copyFile($file, $ifile);
return copyFile($lib, $file, $ifile);
}
######################################################################
@ -534,8 +548,10 @@ sub findFiles {
######################################################################
sub loadSyncProfile {
my ($srcbase, $outbase) = @_;
print("srcbase = $$srcbase \n");
print("outbase = $$outbase \n");
if ($verbose_level) {
print("<srcbase> = $$srcbase \n");
print("<outbase> = $$outbase \n");
}
my $syncprofile = "$$srcbase/sync.profile";
my $result;
@ -627,8 +643,14 @@ while ( @ARGV ) {
$var = "showonly";
$val = "yes";
} elsif($arg eq "-quiet") {
$var = "quiet";
$var = "verbose";
$val = "0";
} elsif($arg eq "-v") {
$var = "verbose";
$val = "yes";
} elsif($arg eq "-verbose") {
$var = "verbose";
$val = shift @ARGV;
} elsif($arg eq "-private") {
$var = "create_private_headers";
$val = "yes";
@ -639,6 +661,9 @@ while ( @ARGV ) {
# skip, it's been dealt with at the top of the file
shift @ARGV;
next;
} elsif($arg eq "-generator") {
$var = "makefile_generator";
$val = shift @ARGV;
} elsif($arg =~/^-/) {
print "Unknown option: $arg\n\n" if(!$var);
showUsage();
@ -667,11 +692,13 @@ while ( @ARGV ) {
} elsif($showonly) {
$showonly--;
}
} elsif ($var eq "quiet") {
} elsif ($var eq "verbose") {
if($val eq "yes") {
$quiet++;
} elsif($quiet) {
$quiet--;
$verbose_level++;
} elsif($val eq "no" && $verbose_level) {
$verbose_level--;
} else {
$verbose_level = int($val);
}
} elsif ($var eq "check-includes") {
if($val eq "yes") {
@ -698,7 +725,7 @@ while ( @ARGV ) {
$force_relative--;
}
} elsif ($var eq "module") {
print "module :$val:\n" unless $quiet;
print "module :$val:\n" if($verbose_level);
die "No such module: $val" unless(defined $modules{$val});
push @modules_to_sync, $val;
} elsif ($var eq "separate-module") {
@ -720,6 +747,8 @@ while ( @ARGV ) {
$cache_module_fwd = 1;
} elsif ($var eq "developer_build") {
$developer_build = 1;
} elsif ($var eq "makefile_generator") {
$makefile_generator = $val;
} elsif ($var eq "no_module_version_header") {
$no_module_version_header = 1;
} elsif ($var eq "output") {
@ -766,9 +795,7 @@ loadSyncProfile(\$basedir, \$out_basedir);
$isunix = checkUnix; #cache checkUnix
# create path
mkpath "$out_basedir/include", !$quiet;
mkpath "$out_basedir/include/Qt", !$quiet;
make_path("$out_basedir/include/Qt", "<outdir>", $verbose_level);
foreach my $lib (@modules_to_sync) {
#iteration info
@ -796,7 +823,7 @@ foreach my $lib (@modules_to_sync) {
chomp $module_patch_version;
}
}
print "WARNING: Module $lib\'s pri missing QT.<module>.VERSION variable! Private headers not versioned!\n" if (!$module_version);
print "$lib: WARNING: Module\'s pri missing QT.<module>.VERSION variable! Private headers not versioned!\n" if (!$module_version);
my $pathtoheaders = "";
$pathtoheaders = $moduleheaders{$lib} if ($moduleheaders{$lib});
@ -870,6 +897,7 @@ foreach my $lib (@modules_to_sync) {
my $modulepri = $modulepris{$lib};
if (-e $modulepri) {
my $modulepriname = basename($modulepri);
# FIXME: this creates a file in the source location for shadow-builds
my $moduleversionheader = "$modules{$lib}/" . lc($lib) . "version.h";
my $modulehexstring = sprintf("0x%02X%02X%02X", int($module_major_version), int($module_minor_version), int($module_patch_version));
open MODULE_VERSION_HEADER_FILE, ">$moduleversionheader";
@ -882,8 +910,11 @@ foreach my $lib (@modules_to_sync) {
print MODULE_VERSION_HEADER_FILE "#define " .uc($lib) . "_VERSION $modulehexstring\n", ;
print MODULE_VERSION_HEADER_FILE "\n";
print MODULE_VERSION_HEADER_FILE "#endif // QT_". uc($lib) . "_VERSION_H\n";
close MODULE_VERSION_HEADER_FILE;
$moduleversionheader = "<srcbase>" . substr($moduleversionheader, length($basedir)) if ($verbose_level < 2);
print "$lib: created version header $moduleversionheader\n" if($verbose_level);
} elsif ($modulepri) {
print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating module version header for $lib.\n";
print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating module version header.\n";
}
}
@ -913,6 +944,7 @@ foreach my $lib (@modules_to_sync) {
push @headers, "*".$if;
}
}
my $header_dirname = "";
foreach my $header (@headers) {
my $shadow = ($header =~ s/^\*//);
$header = 0 if($header =~ /^ui_.*.h/);
@ -979,11 +1011,11 @@ foreach my $lib (@modules_to_sync) {
# class =~ s,::,/,g;
# }
$class_lib_map_contents .= "QT_CLASS_LIB($full_class, $lib, $header_base)\n";
$header_copies++ if(syncHeader("$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
$header_copies++ if(syncHeader($lib, "$out_basedir/include/$lib/$class", "$out_basedir/include/$lib/$header", 0, $ts));
# KDE-Compat headers for Phonon
if ($lib eq "phonon") {
$header_copies++ if (syncHeader("$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts));
$header_copies++ if (syncHeader($lib, "$out_basedir/include/phonon_compat/Phonon/$class", "$out_basedir/include/$lib/$header", 0, $ts));
}
}
} elsif ($create_private_headers) {
@ -994,7 +1026,7 @@ foreach my $lib (@modules_to_sync) {
}
}
foreach(@headers) { #sync them
$header_copies++ if(syncHeader($_, $iheader, $copy_headers && !$shadow, $ts));
$header_copies++ if(syncHeader($lib, $_, $iheader, $copy_headers && !$shadow, $ts));
}
if($public_header) {
@ -1023,9 +1055,29 @@ foreach my $lib (@modules_to_sync) {
$pri_install_pfiles.= "$pri_install_iheader ";;
}
}
print "header created for $iheader ($header_copies)\n" if($header_copies > 0 && !$quiet);
if ($verbose_level && $header_copies) {
my $new_header_dirname = dirname($iheader);
$new_header_dirname = "<srcbase>" . substr($new_header_dirname, length($basedir)) if ($new_header_dirname && $verbose_level < 2);
my $header_base = basename($iheader);
if ($verbose_level < 3) {
my $line_prefix = ",";
if ($new_header_dirname ne $header_dirname) {
$line_prefix = "$lib: created fwd-include header(s) for $new_header_dirname/ {";
$line_prefix = " }\n".$line_prefix if ($header_dirname);
$header_dirname = $new_header_dirname;
} else {
$line_prefix = ",";
}
print "$line_prefix $header_base ($header_copies)";
} else { # $verbose_level >= 3
$iheader = "<srcbase>" . substr($iheader, length($basedir)) if ($verbose_level == 3);
print "$lib: created $header_copies fwd-include headers for $iheader\n";
}
}
}
}
print " }\n" if ($header_dirname && $verbose_level > 0 && $verbose_level < 3);
}
}
@ -1051,11 +1103,11 @@ foreach my $lib (@modules_to_sync) {
}
if($master_include && $master_contents) {
my $master_dir = dirname($master_include);
mkpath $master_dir, !$quiet;
print "header (master) created for $lib\n" unless $quiet;
make_path($master_dir, $lib, $verbose_level);
open MASTERINCLUDE, ">$master_include";
print MASTERINCLUDE $master_contents;
close MASTERINCLUDE;
print "$lib: created header (master) file\n" if($verbose_level);
}
}
@ -1076,11 +1128,11 @@ foreach my $lib (@modules_to_sync) {
}
if($headers_pri_file && $master_contents) {
my $headers_pri_dir = dirname($headers_pri_file);
mkpath $headers_pri_dir, !$quiet;
print "headers.pri file created for $lib\n" unless $quiet;
make_path($headers_pri_dir, $lib, $verbose_level);
open HEADERS_PRI_FILE, ">$headers_pri_file";
print HEADERS_PRI_FILE $headers_pri_contents;
close HEADERS_PRI_FILE;
print "$lib: created headers.pri file\n" if($verbose_level);
}
# create forwarding module pri in qtbase/mkspecs/modules
@ -1088,7 +1140,7 @@ foreach my $lib (@modules_to_sync) {
my $modulepri = $modulepris{$lib};
if (-e $modulepri) {
my $modulepriname = basename($modulepri);
mkpath($module_fwd);
make_path($module_fwd, $lib, $verbose_level);
my $moduleprifwd = "$module_fwd/$modulepriname";
my $mod_base = $developer_build ? $basedir : $out_basedir;
my $mod_component_base = $developer_build ? $qtbasedir : $out_basedir;
@ -1114,7 +1166,7 @@ foreach my $lib (@modules_to_sync) {
}
}
} elsif ($modulepri) {
print "WARNING: Module $lib\'s pri file '$modulepri' not found.\nSkipped creating forwarding pri for $lib.\n";
print "$lib: WARNING: Module\'s pri file '$modulepri' not found.\n$lib: Skipped creating forwarding pri.\n";
}
}
}
@ -1132,7 +1184,7 @@ unless($showonly || !$create_uic_class_map) {
}
if($class_lib_map) {
my $class_lib_map_dir = dirname($class_lib_map);
mkpath $class_lib_map_dir, !$quiet;
make_path($class_lib_map_dir, "<outdir>", $verbose_level);
open CLASS_LIB_MAP, ">$class_lib_map";
print CLASS_LIB_MAP $class_lib_map_contents;
close CLASS_LIB_MAP;
@ -1216,7 +1268,7 @@ if($check_includes) {
if($include) {
for my $trylib (keys(%modules)) {
if(-e "$out_basedir/include/$trylib/$include") {
print "WARNING: $iheader includes $include when it should include $trylib/$include\n";
print "$lib: WARNING: $iheader includes $include when it should include $trylib/$include\n";
}
}
}
@ -1234,27 +1286,27 @@ if($check_includes) {
}
if ($header_skip_qt_begin_header_test == 0) {
if ($qt_begin_header_found == 0) {
print "WARNING: $iheader does not include QT_BEGIN_HEADER\n";
print "$lib: WARNING: $iheader does not include QT_BEGIN_HEADER\n";
}
if ($qt_begin_header_found && $qt_end_header_found == 0) {
print "WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n";
print "$lib: WARNING: $iheader has QT_BEGIN_HEADER but no QT_END_HEADER\n";
}
}
if ($header_skip_qt_begin_namespace_test == 0) {
if ($qt_begin_namespace_found == 0) {
print "WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
print "$lib: WARNING: $iheader does not include QT_BEGIN_NAMESPACE\n";
}
if ($qt_begin_namespace_found && $qt_end_namespace_found == 0) {
print "WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n";
print "$lib: WARNING: $iheader has QT_BEGIN_NAMESPACE but no QT_END_NAMESPACE\n";
}
}
if ($header_skip_qt_module_test == 0) {
if ($qt_module_found == 0) {
print "WARNING: $iheader does not include QT_MODULE\n";
print "$lib: WARNING: $iheader does not include QT_MODULE\n";
}
}
close(F);
@ -1266,4 +1318,21 @@ if($check_includes) {
}
}
# Do configure tests now (pass some things along)
# fatal tests have a non zero return
# If the generator is not set (e.g. someone invoking syncqt as part of configure etc, then don't run tests either)
unless ($showonly || $makefile_generator eq '') {
my $configtests = dirname($0)."/qtmodule-configtests";
if (! -f $configtests) {
$configtests = $qtbasedir."/bin/qtmodule-configtests";
}
if (! -f $configtests) {
warn "Unable to locate qtmodule-configtests script - config tests disabled.\n";
} else {
if (system($EXECUTABLE_NAME, $configtests, $basedir, $out_basedir, $qtbasedir, $makefile_generator)) {
die "$configtests exited with status $?";
}
}
}
exit 0;

10
configure vendored
View File

@ -2577,7 +2577,7 @@ if [ "$OPT_SHADOW" = "yes" ]; then
chmod 755 "$outpath/bin/syncqt"
fi
for i in elf2e32_qtwrapper createpackage patch_capabilities; do
for i in elf2e32_qtwrapper createpackage patch_capabilities qtmodule-configtests; do
rm -f "$outpath/bin/$i"
if [ -x "$relpath/bin/$i" ]; then
mkdir -p "$outpath/bin"
@ -2970,7 +2970,7 @@ if [ '!' -f "${XQMAKESPEC}/qplatformdefs.h" ]; then
echo
echo " $XQMAKESPEC/qplatformdefs.h"
echo
echo " Please contact qt-bugs@trolltech.com."
echo " Please contact qt-info@nokia.com."
echo
exit 2
fi
@ -6911,7 +6911,7 @@ fi
# For "-carbon" builds: 32 bit x86/ppc.
# For builds on snow leopard : compiler default (64-bit).
# For builds on leopard : compiler default (32-bit).
if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_MAC_ARCHS" = "" ]; then
if [ "$CFG_ARCH" = "macosx" ] && [ "$CFG_MAC_ARCHS" = "" ]; then
source "$mactests/defaultarch.test" "$TEST_COMPILER" "$OPT_VERBOSE" "$mactests"
if [ "$CFG_MAC_CARBON" = "yes" ]; then
@ -7150,7 +7150,7 @@ fi
[ "$CFG_AVX" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG avx"
[ "$CFG_IWMMXT" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG iwmmxt"
[ "$CFG_NEON" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG neon"
[ "$PLATFORM_MAC" = "yes" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS"
[ "$CFG_ARCH" = "macosx" ] && QMAKE_CONFIG="$QMAKE_CONFIG $CFG_MAC_ARCHS"
if [ "$CFG_CLOCK_GETTIME" = "yes" ]; then
QT_CONFIG="$QT_CONFIG clock-gettime"
fi
@ -8617,7 +8617,7 @@ else
echo "Building for: $XPLATFORM"
fi
if [ "$PLATFORM_MAC" = "yes" ]; then
if [ ! -z "$CFG_MAC_ARCHS" ]; then
echo "Architecture: $CFG_ARCH ($CFG_MAC_ARCHS )"
else
echo "Architecture: $CFG_ARCH"

3
dist/changes-5.0.0 vendored
View File

@ -17,6 +17,9 @@ information about a particular change.
- Unite clipping support has been removed from QPainter. The alternative is
to unite QRegion's and using the result on QPainter.
- QLibrary::resolve() now returns a function pointer instead of a void
pointer.
****************************************************************************
* General *
****************************************************************************

View File

@ -316,7 +316,7 @@
Now we construct the \c FlippablePad item, passing its column-row count to
its constructor.
The pad is constrolled by three transformations, and we create one
The pad is controlled by three transformations, and we create one
QGraphicsRotation object for each of these.
\list

View File

@ -54,7 +54,7 @@ LocationDialog::LocationDialog(QWidget *parent)
scopeComboBox->addItem(tr("System"));
organizationComboBox = new QComboBox;
organizationComboBox->addItem(tr("Trolltech"));
organizationComboBox->addItem(tr("Qt"));
organizationComboBox->setEditable(true);
applicationComboBox = new QComboBox;

View File

@ -39,4 +39,4 @@ qmake -spec macx-xcode
Then open the generated Xcode project in Xcode and build it.
Feel free to send comments about the tutorial to qt-bugs@trolltech.com.
Feel free to send comments about the tutorial to qt-info@nokia.com.

View File

@ -39,4 +39,4 @@ qmake -spec macx-xcode
Then open the generated Xcode project in Xcode and build it.
Feel free to send comments about the tutorial to qt-bugs@trolltech.com.
Feel free to send comments about the tutorial to qt-info@nokia.com.

View File

@ -0,0 +1 @@
contains(QT, declarative):DEFINES += QT_DECLARATIVE_DEBUG

View File

@ -2,7 +2,7 @@ load(exclusive_builds)
### Qt 5: remove "uic" and "resources" - or add "qt"
CONFIG = lex yacc warn_on debug uic resources $$CONFIG
exists($$_PRO_FILE_PWD_/sync.profile) {
!build_pass:exists($$_PRO_FILE_PWD_/sync.profile) {
PRO_BASENAME = $$basename(_PRO_FILE_)
# Try to detect proper QTDIR path. We require QTDIR, as syncqt uses that to create qt_module.pri
@ -31,7 +31,7 @@ exists($$_PRO_FILE_PWD_/sync.profile) {
qtPrepareTool(QMAKE_SYNCQT, syncqt)
MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -outdir $$OUT_PWD $$_PRO_FILE_PWD_)
MSG = $$quote($$QMAKE_SYNCQT $$QTFWD -generator $$MAKEFILE_GENERATOR -outdir $$OUT_PWD $$_PRO_FILE_PWD_)
!silent:message($$MSG)
system($$MSG) {
# success! Nothing to do

View File

@ -140,7 +140,7 @@ defineTest(qtAddModule) {
}
isEmpty(LINKAGE) {
# Make sure we can link to uninstalled libraries
!isEqual(MODULE_LIBS, $[QT_INSTALL_LIBS]) {
!isEqual(MODULE_LIBS, $$[QT_INSTALL_LIBS]) {
QMAKE_LIBDIR *= $$MODULE_LIBS
unix:!mac:QMAKE_LFLAGS *= "-Wl,-rpath-link,$$MODULE_LIBS"
}

View File

@ -186,6 +186,9 @@ DEFINES *= QT_USE_QSTRINGBUILDER
TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end
qtPrepareTool(QMAKE_MOC, moc)
qtPrepareTool(QMAKE_UIC, uic)
qtPrepareTool(QMAKE_RCC, rcc)
qtPrepareTool(QMAKE_LUPDATE, lupdate)
qtPrepareTool(QMAKE_LRELEASE, lrelease)

View File

@ -1382,16 +1382,15 @@ QMakeProject::read(uchar cmd)
read(Option::mkfile::cachefile, base_vars);
}
}
if(cmd & ReadFeatures) {
debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData());
if(doProjectInclude("default_pre", IncludeFlagFeature, base_vars) == IncludeNoExist)
doProjectInclude("default", IncludeFlagFeature, base_vars);
}
}
vars = base_vars; // start with the base
if(cmd & ReadFeatures) {
debug_msg(1, "Processing default_pre: %s", vars["CONFIG"].join("::").toLatin1().constData());
doProjectInclude("default_pre", IncludeFlagFeature, vars);
}
//get a default
if(pfile != "-" && vars["TARGET"].isEmpty())
vars["TARGET"].append(QFileInfo(pfile).baseName());

View File

@ -135,6 +135,11 @@ syncqt.files=$$QT_BUILD_TREE/bin/syncqt
win32:syncqt.files=$$QT_BUILD_TREE/bin/syncqt.bat
INSTALLS += syncqt
#qtmodule-configtests
configtests.path=$$[QT_INSTALL_BINS]
configtests.files=$$QT_BUILD_TREE/bin/qtmodule-configtests
INSTALLS += configtests
#mkspecs
mkspecs.path=$$[QT_INSTALL_DATA]/mkspecs
mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$files($$QT_SOURCE_TREE/mkspecs/*)

View File

@ -144,7 +144,7 @@ HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch);
int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch);
HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch);
void *HB_Library_Resolve(const char *library, int version, const char *symbol);
void (*HB_Library_Resolve(const char *library, int version, const char *symbol))();
HB_END_HEADER

View File

@ -79,7 +79,7 @@ void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme,
*lineBreak = (HB_LineBreakClass) prop->line_break_class;
}
void *HB_Library_Resolve(const char *library, int version, const char *symbol)
void (*HB_Library_Resolve(const char *library, int version, const char *symbol))()
{
return QLibrary::resolve(library, version, symbol);
}

View File

@ -75,13 +75,34 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue)
return testAndSetOrdered(expectedValue, newValue);
}
inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue)
{
return testAndSetOrdered(expectedValue, newValue);
}
inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd)
{
int returnValue = _q_value;
_q_value += valueToAdd;
return returnValue;
}
inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd)
{
return fetchAndAddOrdered(valueToAdd);
}
inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd)
{
return fetchAndAddOrdered(valueToAdd);
}
inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd)
{
return fetchAndAddOrdered(valueToAdd);
}
template <typename T>
Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue)
{

View File

@ -718,6 +718,13 @@ QT_BEGIN_NAMESPACE
\sa QtMsgHandler, qInstallMsgHandler()
*/
/*! \typedef QFunctionPointer
\relates <QtGlobal>
This is a typedef for \c{void (*)()}, a pointer to a function that takes
no arguments and returns void.
*/
/*! \macro qint64 Q_INT64_C(literal)
\relates <QtGlobal>

View File

@ -281,7 +281,7 @@ namespace QT_NAMESPACE {}
# define Q_OS_VXWORKS
#elif defined(__MAKEDEPEND__)
#else
# error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com"
# error "Qt has not been ported to this OS - talk to qt-info@nokia.com"
#endif
#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE)
@ -794,7 +794,7 @@ namespace QT_NAMESPACE {}
# define Q_CC_NOKIAX86
#else
# error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com"
# error "Qt has not been tested with this compiler - talk to qt-info@nokia.com"
#endif
@ -1807,6 +1807,8 @@ Q_CORE_EXPORT void qt_message_output(QtMsgType, const char *buf);
typedef void (*QtMsgHandler)(QtMsgType, const char *);
Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
typedef void (*QFunctionPointer)();
#if !defined(Q_UNIMPLEMENTED)
# define Q_UNIMPLEMENTED() qWarning("%s:%d: %s: Unimplemented code.", __FILE__, __LINE__, Q_FUNC_INFO)
#endif

View File

@ -131,7 +131,7 @@
# define __NR_inotify_rm_watch 286
# define __NR_inotify_init1 328
#else
# error "This architecture is not supported. Please talk to qt-bugs@trolltech.com"
# error "This architecture is not supported. Please talk to qt-info@nokia.com"
#endif
#if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1)

View File

@ -45,109 +45,10 @@
#include "qthread.h"
#include <private/qthread_p.h>
#include <private/qcoreapplication_p.h>
#include <private/qfreelist_p.h>
QT_BEGIN_NAMESPACE
// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers
static const int TimerIdMask = 0x00ffffff;
static const int TimerSerialMask = ~TimerIdMask & ~0x80000000;
static const int TimerSerialCounter = TimerIdMask + 1;
static const int MaxTimerId = TimerIdMask;
static int FirstBucket[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
};
enum {
FirstBucketOffset = 0,
SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]),
ThirdBucketOffset = 0x100,
FourthBucketOffset = 0x1000,
FifthBucketOffset = 0x10000,
SixthBucketOffset = 0x100000
};
enum {
FirstBucketSize = SecondBucketOffset,
SecondBucketSize = ThirdBucketOffset - SecondBucketOffset,
ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset,
FourthBucketSize = FifthBucketOffset - FourthBucketOffset,
FifthBucketSize = SixthBucketOffset - FifthBucketOffset,
SixthBucketSize = MaxTimerId - SixthBucketOffset
};
static const int BucketSize[] = {
FirstBucketSize, SecondBucketSize, ThirdBucketSize,
FourthBucketSize, FifthBucketSize, SixthBucketSize
};
enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) };
static const int BucketOffset[] = {
FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset,
FourthBucketOffset, FifthBucketOffset, SixthBucketOffset
};
static QBasicAtomicPointer<int> timerIds[] =
{ Q_BASIC_ATOMIC_INITIALIZER(FirstBucket),
Q_BASIC_ATOMIC_INITIALIZER(0),
Q_BASIC_ATOMIC_INITIALIZER(0),
Q_BASIC_ATOMIC_INITIALIZER(0),
Q_BASIC_ATOMIC_INITIALIZER(0),
Q_BASIC_ATOMIC_INITIALIZER(0) };
static void timerIdsDestructorFunction()
{
// start at one, the first bucket is pre-allocated
for (int i = 1; i < NumberOfBuckets; ++i)
delete [] static_cast<int *>(timerIds[i]);
}
Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction)
static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1);
// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number
static inline int prepareNewValueWithSerialNumber(int oldId, int newId)
{
return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask);
}
namespace {
template<bool> struct QStaticAssertType;
template<> struct QStaticAssertType<true> { enum { Value = 1 }; };
}
#define q_static_assert(expr) (void)QStaticAssertType<expr>::Value
static inline int bucketOffset(int timerId)
{
q_static_assert(sizeof BucketSize == sizeof BucketOffset);
q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets);
for (int i = 0; i < NumberOfBuckets; ++i) {
if (timerId < BucketSize[i])
return i;
timerId -= BucketSize[i];
}
qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId);
return -1;
}
static inline int bucketIndex(int bucket, int timerId)
{
return timerId - BucketOffset[bucket];
}
static inline int *allocateBucket(int bucket)
{
// allocate a new bucket
const int size = BucketSize[bucket];
const int offset = BucketOffset[bucket];
int *b = new int[size];
for (int i = 0; i != size; ++i)
b[i] = offset + i + 1;
return b;
}
void QAbstractEventDispatcherPrivate::init()
{
Q_Q(QAbstractEventDispatcher);
@ -158,79 +59,54 @@ void QAbstractEventDispatcherPrivate::init()
}
}
// Timer IDs are implemented using a free-list;
// there's a vector initialized with:
// X[i] = i + 1
// and nextFreeTimerId starts with 1.
//
// Allocating a timer ID involves taking the ID from
// X[nextFreeTimerId]
// updating nextFreeTimerId to this value and returning the old value
//
// When the timer ID is allocated, its cell in the vector is unused (it's a
// free list). As an added protection, we use the cell to store an invalid
// (negative) value that we can later check for integrity.
//
// (continues below).
// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers
struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants
{
enum
{
InitialNextValue = 1,
BlockCount = 6,
};
static const int Sizes[BlockCount];
};
enum {
Offset0 = 0x00000000,
Offset1 = 0x00000040,
Offset2 = 0x00000100,
Offset3 = 0x00001000,
Offset4 = 0x00010000,
Offset5 = 0x00100000,
Size0 = Offset1 - Offset0,
Size1 = Offset2 - Offset1,
Size2 = Offset3 - Offset2,
Size3 = Offset4 - Offset3,
Size4 = Offset5 - Offset4,
Size5 = QtTimerIdFreeListConstants::MaxIndex - Offset5
};
const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstants::BlockCount] = {
Size0,
Size1,
Size2,
Size3,
Size4,
Size5
};
typedef QFreeList<void, QtTimerIdFreeListConstants> QtTimerIdFreeList;
Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList)
int QAbstractEventDispatcherPrivate::allocateTimerId()
{
int timerId, newTimerId;
int at, *b;
do {
timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics
// which bucket are we looking in?
int which = timerId & TimerIdMask;
int bucket = bucketOffset(which);
at = bucketIndex(bucket, which);
b = timerIds[bucket];
if (!b) {
// allocate a new bucket
b = allocateBucket(bucket);
if (!timerIds[bucket].testAndSetRelease(0, b)) {
// another thread won the race to allocate the bucket
delete [] b;
b = timerIds[bucket];
}
}
newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]);
} while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId));
b[at] = -timerId;
return timerId;
return timerIdFreeList()->next();
}
// Releasing a timer ID requires putting the current ID back in the vector;
// we do it by setting:
// X[timerId] = nextFreeTimerId;
// then we update nextFreeTimerId to the timer we've just released
//
// The extra code in allocateTimerId and releaseTimerId are ABA prevention
// and bucket memory. The buckets are simply to make sure we allocate only
// the necessary number of timers. See above.
//
// ABA prevention simply adds a value to 7 of the top 8 bits when resetting
// nextFreeTimerId.
void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
{
int which = timerId & TimerIdMask;
int bucket = bucketOffset(which);
int at = bucketIndex(bucket, which);
int *b = timerIds[bucket];
Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId",
"Internal error: timer ID not found");
int freeId, newTimerId;
do {
freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics
b[at] = freeId & TimerIdMask;
newTimerId = prepareNewValueWithSerialNumber(freeId, timerId);
} while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId));
timerIdFreeList()->release(timerId);
}
/*!

View File

@ -859,20 +859,31 @@ QMetaProperty QMetaObject::property(int index) const
if (flags & EnumOrFlag) {
result.menum = enumerator(indexOfEnumerator(type));
if (!result.menum.isValid()) {
QByteArray enum_name = type;
QByteArray scope_name = d.stringdata;
int s = enum_name.lastIndexOf("::");
if (s > 0) {
scope_name = enum_name.left(s);
enum_name = enum_name.mid(s + 2);
const char *enum_name = type;
const char *scope_name = d.stringdata;
char *scope_buffer = 0;
const char *colon = strrchr(enum_name, ':');
// ':' will always appear in pairs
Q_ASSERT(colon <= enum_name || *(colon-1) == ':');
if (colon > enum_name) {
int len = colon-enum_name-1;
scope_buffer = (char *)qMalloc(len+1);
qMemCopy(scope_buffer, enum_name, len);
scope_buffer[len] = '\0';
scope_name = scope_buffer;
enum_name = colon+1;
}
const QMetaObject *scope = 0;
if (scope_name == "Qt")
if (qstrcmp(scope_name, "Qt") == 0)
scope = &QObject::staticQtMetaObject;
else
scope = QMetaObject_findMetaObject(this, scope_name);
if (scope)
result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name));
if (scope_buffer)
qFree(scope_buffer);
}
}
}

View File

@ -101,7 +101,8 @@ enum MethodFlags {
};
enum MetaObjectFlags {
DynamicMetaObject = 0x01
DynamicMetaObject = 0x01,
RequiresVariantMetaObject = 0x02
};
class QMutex;

View File

@ -60,7 +60,6 @@
#include <qsharedpointer.h>
#include <private/qorderedmutexlocker_p.h>
#include <private/qmutexpool_p.h>
#include <new>
@ -95,35 +94,22 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames)
return types;
}
static QBasicAtomicPointer<QMutexPool> signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0);
static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0);
static QBasicMutex _q_ObjectMutexPool[131];
/** \internal
* mutex to be locked when accessing the connectionlists or the senders list
*/
static inline QMutex *signalSlotLock(const QObject *o)
{
if (!signalSlotMutexes) {
QMutexPool *mp = new QMutexPool;
if (!signalSlotMutexes.testAndSetOrdered(0, mp)) {
delete mp;
}
}
return signalSlotMutexes->get(o);
return static_cast<QMutex *>(&_q_ObjectMutexPool[
uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]);
}
extern "C" Q_CORE_EXPORT void qt_addObject(QObject *)
{
objectCount.ref();
}
{}
extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
{
if(!objectCount.deref()) {
QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0);
delete old;
}
}
{}
struct QConnectionSenderSwitcher {
QObject *receiver;
@ -879,7 +865,7 @@ QObject::~QObject()
if (c->next) c->next->prev = c->prev;
}
if (needToUnlock)
m->unlockInline();
m->unlock();
connectionList.first = c->nextConnectionList;
delete c;
@ -903,7 +889,7 @@ QObject::~QObject()
bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m);
//the node has maybe been removed while the mutex was unlocked in relock?
if (!node || node->sender != sender) {
m->unlockInline();
m->unlock();
continue;
}
node->receiver = 0;
@ -913,7 +899,7 @@ QObject::~QObject()
node = node->next;
if (needToUnlock)
m->unlockInline();
m->unlock();
}
}
@ -3077,7 +3063,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c,
}
if (needToUnlock)
receiverMutex->unlockInline();
receiverMutex->unlock();
c->receiver = 0;

View File

@ -447,7 +447,7 @@ QLibraryPrivate::~QLibraryPrivate()
}
}
void *QLibraryPrivate::resolve(const char *symbol)
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
{
if (!pHnd)
return 0;
@ -1129,7 +1129,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver
Note: In Symbian resolving with symbol names works only if the loaded
library was built as STDDLL. Otherwise, the ordinals must be used.
*/
void *QLibrary::resolve(const char *symbol)
QFunctionPointer QLibrary::resolve(const char *symbol)
{
if (!isLoaded() && !load())
return 0;
@ -1152,7 +1152,7 @@ void *QLibrary::resolve(const char *symbol)
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, const char *symbol)
QFunctionPointer QLibrary::resolve(const QString &fileName, const char *symbol)
{
QLibrary library(fileName);
return library.resolve(symbol);
@ -1175,7 +1175,7 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol)
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
QFunctionPointer QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
{
QLibrary library(fileName, verNum);
return library.resolve(symbol);
@ -1199,7 +1199,7 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol)
\sa resolve()
*/
void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol)
{
QLibrary library(fileName, version);
return library.resolve(symbol);

View File

@ -79,10 +79,10 @@ public:
explicit QLibrary(const QString& fileName, const QString &version, QObject *parent = 0);
~QLibrary();
void *resolve(const char *symbol);
static void *resolve(const QString &fileName, const char *symbol);
static void *resolve(const QString &fileName, int verNum, const char *symbol);
static void *resolve(const QString &fileName, const QString &version, const char *symbol);
QFunctionPointer resolve(const char *symbol);
static QFunctionPointer resolve(const QString &fileName, const char *symbol);
static QFunctionPointer resolve(const QString &fileName, int verNum, const char *symbol);
static QFunctionPointer resolve(const QString &fileName, const QString &version, const char *symbol);
bool load();
bool unload();

View File

@ -87,7 +87,7 @@ public:
bool loadPlugin(); // loads and resolves instance
bool unload();
void release();
void *resolve(const char *);
QFunctionPointer resolve(const char *);
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString());
@ -108,7 +108,7 @@ private:
bool load_sys();
bool unload_sys();
void *resolve_sys(const char *);
QFunctionPointer resolve_sys(const char *);
QAtomicInt libraryRefCount;
QAtomicInt libraryUnloadCount;

View File

@ -267,29 +267,29 @@ bool QLibraryPrivate::unload_sys()
}
#ifdef Q_OS_MAC
Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol)
Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symbol)
{
return dlsym(handle, symbol);
return QFunctionPointer(dlsym(handle, symbol));
}
#endif
void* QLibraryPrivate::resolve_sys(const char* symbol)
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
{
#if defined(QT_AOUT_UNDERSCORE)
// older a.out systems add an underscore in front of symbols
char* undrscr_symbol = new char[strlen(symbol)+2];
undrscr_symbol[0] = '_';
strcpy(undrscr_symbol+1, symbol);
void* address = dlsym(pHnd, undrscr_symbol);
QFunctionPointer address = QFunctionPointer(dlsym(pHnd, undrscr_symbol));
delete [] undrscr_symbol;
#elif defined(QT_HPUX_LD)
void* address = 0;
QFunctionPointer address = 0;
if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0)
address = 0;
#elif defined (QT_NO_DYNAMIC_LIBRARY)
void *address = 0;
QFunctionPointer address = 0;
#else
void* address = dlsym(pHnd, symbol);
QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol));
#endif
if (!address) {
errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(

View File

@ -113,12 +113,12 @@ bool QLibraryPrivate::unload_sys()
return true;
}
void* QLibraryPrivate::resolve_sys(const char* symbol)
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
{
#ifdef Q_OS_WINCE
void* address = (void*)GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16());
FARPROC address = GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16());
#else
void* address = (void*)GetProcAddress(pHnd, symbol);
FARPROC address = GetProcAddress(pHnd, symbol);
#endif
if (!address) {
errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(
@ -126,6 +126,6 @@ void* QLibraryPrivate::resolve_sys(const char* symbol)
} else {
errorString.clear();
}
return address;
return QFunctionPointer(address);
}
QT_END_NAMESPACE

View File

@ -78,20 +78,20 @@ public:
return (m_handle != 0);
}
void *resolve(const char *symbol)
QFunctionPointer resolve(const char *symbol)
{
if (!m_didLoad)
load();
if (!m_handle)
return 0;
#ifdef Q_OS_WINCE
return (void*)GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16());
return QFunctionPointer(GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16()));
#else
return (void*)GetProcAddress(m_handle, symbol);
return QFunctionPointer(GetProcAddress(m_handle, symbol));
#endif
}
static void *resolve(const QString &libraryName, const char *symbol)
static QFunctionPointer resolve(const QString &libraryName, const char *symbol)
{
return QSystemLibrary(libraryName).resolve(symbol);
}

View File

@ -49,8 +49,25 @@
#include "qthread.h"
#include "qmutex_p.h"
#ifndef Q_OS_LINUX
#include "private/qfreelist_p.h"
#endif
QT_BEGIN_NAMESPACE
/*!
\class QBasicMutex
\brief QMutex POD
\internal
\ingroup thread
- Can be used as global static object.
- Always non-recursive
- Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor)
*/
/*!
\class QMutex
\brief The QMutex class provides access serialization between threads.
@ -122,8 +139,12 @@ QT_BEGIN_NAMESPACE
\sa lock(), unlock()
*/
QMutex::QMutex(RecursionMode mode)
: d(new QMutexPrivate(mode))
{ }
{
if (mode == Recursive)
d = new QRecursiveMutexPrivate;
else
d = 0;
}
/*!
Destroys the mutex.
@ -131,9 +152,18 @@ QMutex::QMutex(RecursionMode mode)
\warning Destroying a locked mutex may result in undefined behavior.
*/
QMutex::~QMutex()
{ delete static_cast<QMutexPrivate *>(d); }
{
if (isRecursive())
delete static_cast<QRecursiveMutexPrivate *>(d._q_value);
else if (d) {
#ifndef Q_OS_LINUX
if (d->possiblyUnlocked && tryLock()) { unlock(); return; }
#endif
qWarning("QMutex: destroying locked mutex");
}
}
/*!
/*! \fn void QMutex::lock()
Locks the mutex. If another thread has locked the mutex then this
call will block until that thread has unlocked it.
@ -145,40 +175,8 @@ QMutex::~QMutex()
\sa unlock()
*/
void QMutex::lock()
{
QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
self = QThread::currentThreadId();
if (d->owner == self) {
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
return;
}
bool isLocked = d->contenders.testAndSetAcquire(0, 1);
if (!isLocked) {
// didn't get the lock, wait for it
isLocked = d->wait();
Q_ASSERT_X(isLocked, "QMutex::lock",
"Internal error, infinite wait has timed out.");
}
d->owner = self;
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter");
return;
}
bool isLocked = d->contenders.testAndSetAcquire(0, 1);
if (!isLocked) {
lockInternal();
}
}
/*!
/*!\fn bool QMutex::trylock()
Attempts to lock the mutex. If the lock was obtained, this function
returns true. If another thread has locked the mutex, this
function returns false immediately.
@ -195,36 +193,9 @@ void QMutex::lock()
\sa lock(), unlock()
*/
bool QMutex::tryLock()
{
QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
self = QThread::currentThreadId();
if (d->owner == self) {
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
return true;
}
bool isLocked = d->contenders.testAndSetAcquire(0, 1);
if (!isLocked) {
// some other thread has the mutex locked, or we tried to
// recursively lock an non-recursive mutex
return isLocked;
}
d->owner = self;
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
return isLocked;
}
return d->contenders.testAndSetAcquire(0, 1);
}
/*! \overload
/*! \fn bool QMutex::tryLock(int timeout)
\overload
Attempts to lock the mutex. This function returns true if the lock
was obtained; otherwise it returns false. If another thread has
@ -247,81 +218,30 @@ bool QMutex::tryLock()
\sa lock(), unlock()
*/
bool QMutex::tryLock(int timeout)
{
QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
self = QThread::currentThreadId();
if (d->owner == self) {
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
return true;
}
bool isLocked = d->contenders.testAndSetAcquire(0, 1);
if (!isLocked) {
// didn't get the lock, wait for it
isLocked = d->wait(timeout);
if (!isLocked)
return false;
}
d->owner = self;
++d->count;
Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter");
return true;
}
return (d->contenders.testAndSetAcquire(0, 1)
// didn't get the lock, wait for it
|| d->wait(timeout));
}
/*!
/*! \fn void QMutex::unlock()
Unlocks the mutex. Attempting to unlock a mutex in a different
thread to the one that locked it results in an error. Unlocking a
mutex that is not locked results in undefined behavior.
\sa lock()
*/
void QMutex::unlock()
{
QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
if (d->recursive) {
if (!--d->count) {
d->owner = 0;
if (!d->contenders.testAndSetRelease(1, 0))
d->wakeUp();
}
} else {
if (!d->contenders.testAndSetRelease(1, 0))
d->wakeUp();
}
}
/*!
\fn bool QMutex::locked()
\fn void QMutex::isRecursive()
\since 5.0
Returns true if the mutex is locked by another thread; otherwise
returns false.
Returns true if the mutex is recursive
It is generally a bad idea to use this function, because code
that uses it has a race condition. Use tryLock() and unlock()
instead.
\oldcode
bool isLocked = mutex.locked();
\newcode
bool isLocked = true;
if (mutex.tryLock()) {
mutex.unlock();
isLocked = false;
}
\endcode
*/
bool QBasicMutex::isRecursive() {
QMutexPrivate *d = this->d;
if (quintptr(d) <= 0x3)
return false;
return d->recursive;
}
/*!
\class QMutexLocker
@ -418,96 +338,217 @@ void QMutex::unlock()
\sa unlock()
*/
#ifndef Q_OS_LINUX //linux implementation is in qmutex_linux.cpp
/*!
\fn QMutex::QMutex(bool recursive)
Use the constructor that takes a RecursionMode parameter instead.
*/
/*!
\internal helper for lockInline()
\internal helper for lock()
*/
void QMutex::lockInternal()
bool QBasicMutex::lockInternal(int timeout)
{
QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
while (!fastTryLock()) {
QMutexPrivate *d = this->d;
if (!d) // if d is 0, the mutex is unlocked
continue;
if (QThread::idealThreadCount() == 1) {
// don't spin on single cpu machines
bool isLocked = d->wait();
Q_ASSERT_X(isLocked, "QMutex::lock",
"Internal error, infinite wait has timed out.");
Q_UNUSED(isLocked);
return;
}
QElapsedTimer elapsedTimer;
elapsedTimer.start();
do {
qint64 spinTime = elapsedTimer.nsecsElapsed();
if (spinTime > d->maximumSpinTime) {
// didn't get the lock, wait for it, since we're not going to gain anything by spinning more
elapsedTimer.start();
bool isLocked = d->wait();
Q_ASSERT_X(isLocked, "QMutex::lock",
"Internal error, infinite wait has timed out.");
Q_UNUSED(isLocked);
qint64 maximumSpinTime = d->maximumSpinTime;
qint64 averageWaitTime = d->averageWaitTime;
qint64 actualWaitTime = elapsedTimer.nsecsElapsed();
if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) {
// measure the wait times
averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
if (d == dummyLocked()) {
if (timeout == 0)
return false;
QMutexPrivate *newD = QMutexPrivate::allocate();
if (!this->d.testAndSetOrdered(d, newD)) {
//Either the mutex is already unlocked, or another thread already set it.
newD->deref();
continue;
}
// adjust the spin count when spinning does not benefit contention performance
if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) {
// long waits, stop spinning
d->maximumSpinTime = 0;
} else {
// allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse)
d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
}
return;
d = newD;
//the d->refCount is already 1 the deref will occurs when we unlock
} else if (d->recursive) {
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout);
}
// be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not
QThread::yieldCurrentThread();
} while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1));
// spinning is working, do not change the spin time (unless we are using much less time than allowed to spin)
qint64 maximumSpinTime = d->maximumSpinTime;
qint64 spinTime = elapsedTimer.nsecsElapsed();
if (spinTime < maximumSpinTime / 2) {
// we are using much less time than we need, adjust the limit
d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold));
if (timeout == 0 && !d->possiblyUnlocked)
return false;
if (!d->ref())
continue; //that QMutexPrivate was already released
if (d != this->d) {
//Either the mutex is already unlocked, or relocked with another mutex
d->deref();
continue;
}
int old_waiters;
do {
old_waiters = d->waiters;
if (old_waiters == -QMutexPrivate::BigNumber) {
// we are unlocking, and the thread that unlocks is about to change d to 0
// we try to aquire the mutex by changing to dummyLocked()
if (this->d.testAndSetAcquire(d, dummyLocked())) {
// Mutex aquired
Q_ASSERT(d->waiters == -QMutexPrivate::BigNumber || d->waiters == 0);
d->waiters = 0;
d->deref();
return true;
} else {
Q_ASSERT(d != this->d); //else testAndSetAcquire should have succeeded
// Mutex is likely to bo 0, we should continue the outer-loop,
// set old_waiters to the magic value of BigNumber
old_waiters = QMutexPrivate::BigNumber;
break;
}
}
} while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1));
if (d != this->d) {
// Mutex was unlocked.
if (old_waiters != QMutexPrivate::BigNumber) {
//we did not break the previous loop
Q_ASSERT(d->waiters >= 1);
d->waiters.deref();
}
d->deref();
continue;
}
if (d->wait(timeout)) {
if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false))
d->deref();
d->derefWaiters(1);
//we got the lock. (do not deref)
Q_ASSERT(d == this->d);
return true;
} else {
Q_ASSERT(timeout >= 0);
//timeout
d->derefWaiters(1);
//There may be a race in which the mutex is unlocked right after we timed out,
// and before we deref the waiters, so maybe the mutex is actually unlocked.
if (!d->possiblyUnlocked.testAndSetRelaxed(false, true))
d->deref();
return false;
}
}
Q_ASSERT(this->d);
return true;
}
/*!
\internal
*/
void QMutex::unlockInternal()
void QBasicMutex::unlockInternal()
{
static_cast<QMutexPrivate *>(d)->wakeUp();
QMutexPrivate *d = this->d;
Q_ASSERT(d); //we must be locked
Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
if (d->recursive) {
static_cast<QRecursiveMutexPrivate *>(d)->unlock();
return;
}
if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {
//there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0)
if (this->d.testAndSetRelease(d, 0)) {
if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false))
d->deref();
}
d->derefWaiters(0);
} else {
d->derefWaiters(0);
//there are thread waiting, transfer the lock.
d->wakeUp();
}
d->deref();
}
//The freelist managment
namespace {
struct FreeListConstants : QFreeListDefaultConstants {
enum { BlockCount = 4, MaxIndex=0xffff };
static const int Sizes[BlockCount];
};
const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = {
16,
128,
1024,
FreeListConstants::MaxIndex - (16-128-1024)
};
typedef QFreeList<QMutexPrivate, FreeListConstants> FreeList;
Q_GLOBAL_STATIC(FreeList, freelist);
}
QMutexPrivate *QMutexPrivate::allocate()
{
int i = freelist()->next();
QMutexPrivate *d = &(*freelist())[i];
d->id = i;
Q_ASSERT(d->refCount == 0);
Q_ASSERT(!d->recursive);
Q_ASSERT(!d->possiblyUnlocked);
Q_ASSERT(d->waiters == 0);
d->refCount = 1;
return d;
}
void QMutexPrivate::release()
{
Q_ASSERT(!recursive);
Q_ASSERT(refCount == 0);
Q_ASSERT(!possiblyUnlocked);
Q_ASSERT(waiters == 0);
freelist()->release(id);
}
// atomically substract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag
void QMutexPrivate::derefWaiters(int value)
{
int old_waiters;
int new_waiters;
do {
old_waiters = waiters;
new_waiters = old_waiters;
if (new_waiters < 0) {
new_waiters += QMutexPrivate::BigNumber;
}
new_waiters -= value;
} while (!waiters.testAndSetRelaxed(old_waiters, new_waiters));
}
#endif
/*!
\internal
*/
bool QRecursiveMutexPrivate::lock(int timeout) {
Qt::HANDLE self = QThread::currentThreadId();
if (owner == self) {
++count;
Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter");
return true;
}
bool success = true;
if (timeout == -1) {
mutex.lock();
} else {
success = mutex.tryLock(timeout);
}
if (success)
owner = self;
return success;
}
/*!
\fn QMutex::lockInline()
\internal
inline version of QMutex::lock()
*/
/*!
\fn QMutex::unlockInline()
\internal
inline version of QMutex::unlock()
*/
/*!
\fn QMutex::tryLockInline()
\internal
inline version of QMutex::tryLock()
*/
*/
void QRecursiveMutexPrivate::unlock()
{
if (count > 0) {
count--;
} else {
owner = 0;
mutex.unlock();
}
}
QT_END_NAMESPACE

View File

@ -52,47 +52,64 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Core)
#ifndef QT_NO_THREAD
#if !defined(QT_NO_THREAD) && !defined(qdoc)
class QAtomicInt;
class QMutexData;
class QMutexPrivate;
class Q_CORE_EXPORT QMutex
class Q_CORE_EXPORT QBasicMutex
{
friend class QWaitCondition;
friend class QWaitConditionPrivate;
public:
enum RecursionMode { NonRecursive, Recursive };
inline void lock() {
if (!fastTryLock())
lockInternal();
}
explicit QMutex(RecursionMode mode = NonRecursive);
~QMutex();
inline void unlock() {
Q_ASSERT(d); //mutex must be locked
if (!d.testAndSetRelease(dummyLocked(), 0))
unlockInternal();
}
void lock(); //### Qt5: make inline;
inline void lockInline();
bool tryLock(); //### Qt5: make inline;
bool tryLock(int timeout);
inline bool tryLockInline();
void unlock(); //### Qt5: make inline;
inline void unlockInline();
bool tryLock(int timeout = 0) {
return fastTryLock() || lockInternal(timeout);
}
bool isRecursive();
private:
void lockInternal();
inline bool fastTryLock() {
return d.testAndSetAcquire(0, dummyLocked());
}
bool lockInternal(int timeout = -1);
void unlockInternal();
Q_DISABLE_COPY(QMutex)
QMutexData *d;
QBasicAtomicPointer<QMutexPrivate> d;
static inline QMutexPrivate *dummyLocked() {
return reinterpret_cast<QMutexPrivate *>(quintptr(1));
}
friend class QMutex;
friend class QMutexPrivate;
};
class Q_CORE_EXPORT QMutex : public QBasicMutex {
public:
enum RecursionMode { NonRecursive, Recursive };
explicit QMutex(RecursionMode mode = NonRecursive);
~QMutex();
private:
Q_DISABLE_COPY(QMutex)
};
class Q_CORE_EXPORT QMutexLocker
{
public:
inline explicit QMutexLocker(QMutex *m)
inline explicit QMutexLocker(QBasicMutex *m)
{
Q_ASSERT_X((reinterpret_cast<quintptr>(m) & quintptr(1u)) == quintptr(0),
"QMutexLocker", "QMutex pointer is misaligned");
if (m) {
m->lockInline();
m->lock();
val = reinterpret_cast<quintptr>(m) | quintptr(1u);
} else {
val = 0;
@ -104,7 +121,7 @@ public:
{
if ((val & quintptr(1u)) == quintptr(1u)) {
val &= ~quintptr(1u);
mutex()->unlockInline();
mutex()->unlock();
}
}
@ -112,7 +129,7 @@ public:
{
if (val) {
if ((val & quintptr(1u)) == quintptr(0u)) {
mutex()->lockInline();
mutex()->lock();
val |= quintptr(1u);
}
}
@ -138,54 +155,9 @@ private:
quintptr val;
};
class QMutexData
{
public:
QAtomicInt contenders;
const uint recursive : 1;
uint reserved : 31;
protected:
QMutexData(QMutex::RecursionMode mode);
~QMutexData();
};
#ifdef QT_NO_DEBUG
inline void QMutex::unlockInline()
{
if (d->recursive) {
unlock();
} else if (!d->contenders.testAndSetRelease(1, 0)) {
unlockInternal();
}
}
inline bool QMutex::tryLockInline()
{
if (d->recursive) {
return tryLock();
} else {
return d->contenders.testAndSetAcquire(0, 1);
}
}
inline void QMutex::lockInline()
{
if (d->recursive) {
lock();
} else if(!tryLockInline()) {
lockInternal();
}
}
#else // QT_NO_DEBUG
//in debug we do not use inline calls in order to allow debugging tools
// to hook the mutex locking functions.
inline void QMutex::unlockInline() { unlock(); }
inline bool QMutex::tryLockInline() { return tryLock(); }
inline void QMutex::lockInline() { lock(); }
#endif // QT_NO_DEBUG
#else // QT_NO_THREAD
#else // QT_NO_THREAD or qdoc
class Q_CORE_EXPORT QMutex
@ -194,14 +166,11 @@ public:
enum RecursionMode { NonRecursive, Recursive };
inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); }
inline ~QMutex() {}
static inline void lock() {}
static inline void lockInline() {}
static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; }
static inline bool tryLockInline() { return true; }
static inline void unlock() {}
static inline void unlockInline() {}
static inline bool isRecursive() { return true; }
private:
Q_DISABLE_COPY(QMutex)
@ -221,7 +190,9 @@ private:
Q_DISABLE_COPY(QMutexLocker)
};
#endif // QT_NO_THREAD
typedef QMutex QBasicMutex;
#endif // QT_NO_THREAD or qdoc
QT_END_NAMESPACE

View File

@ -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 QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qplatformdefs.h"
#include "qmutex.h"
#ifndef QT_NO_THREAD
#include "qatomic.h"
#include "qmutex_p.h"
# include "qelapsedtimer.h"
#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <errno.h>
QT_BEGIN_NAMESPACE
static inline int _q_futex(QMutexPrivate *volatile *addr, int op, int val, const struct timespec *timeout)
{
volatile int *int_addr = reinterpret_cast<volatile int *>(addr);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8
int_addr++; //We want a pointer to the 32 least significant bit of QMutex::d
#endif
int *addr2 = 0;
int val2 = 0;
return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2);
}
static inline QMutexPrivate *dummyFutexValue()
{
return reinterpret_cast<QMutexPrivate *>(quintptr(3));
}
QMutexPrivate::~QMutexPrivate() {}
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: recursive(mode == QMutex::Recursive) {}
bool QBasicMutex::lockInternal(int timeout)
{
QElapsedTimer elapsedTimer;
if (timeout >= 1)
elapsedTimer.start();
while (!fastTryLock()) {
QMutexPrivate *d = this->d;
if (!d) // if d is 0, the mutex is unlocked
continue;
if (quintptr(d) <= 0x3) { //d == dummyLocked() || d == dummyFutexValue()
if (timeout == 0)
return false;
while (this->d.fetchAndStoreAcquire(dummyFutexValue()) != 0) {
struct timespec ts, *pts = 0;
if (timeout >= 1) {
// recalculate the timeout
qint64 xtimeout = timeout * 1000 * 1000;
xtimeout -= elapsedTimer.nsecsElapsed();
if (xtimeout <= 0) {
// timer expired after we returned
return false;
}
ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000;
ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000);
pts = &ts;
}
int r = _q_futex(&this->d._q_value, FUTEX_WAIT, quintptr(dummyFutexValue()), pts);
if (r != 0 && errno == ETIMEDOUT)
return false;
}
return true;
}
Q_ASSERT(d->recursive);
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout);
}
Q_ASSERT(this->d);
return true;
}
void QBasicMutex::unlockInternal()
{
QMutexPrivate *d = this->d;
Q_ASSERT(d); //we must be locked
Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
if (d == dummyFutexValue()) {
this->d.fetchAndStoreRelease(0);
_q_futex(&this->d._q_value, FUTEX_WAKE, 1, 0);
return;
}
Q_ASSERT(d->recursive);
static_cast<QRecursiveMutexPrivate *>(d)->unlock();
}
QT_END_NAMESPACE
#endif // QT_NO_THREAD

View File

@ -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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qplatformdefs.h"
#include "qmutex.h"
#if !defined(QT_NO_THREAD)
#include "qmutex_p.h"
#include <mach/mach.h>
#include <mach/task.h>
#include <errno.h>
QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: recursive(mode == QMutex::Recursive)
{
kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0);
if (r != KERN_SUCCESS)
qWarning("QMutex: failed to create semaphore, error %d", r);
}
QMutexPrivate::~QMutexPrivate()
{
kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore);
if (r != KERN_SUCCESS)
qWarning("QMutex: failed to destroy semaphore, error %d", r);
}
bool QMutexPrivate::wait(int timeout)
{
kern_return_t r;
if (timeout < 0) {
do {
r = semaphore_wait(mach_semaphore);
} while (r == KERN_ABORTED);
Q_ASSERT(r == KERN_SUCCESS);
} else {
mach_timespec_t ts;
ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
ts.tv_sec = (timeout / 1000);
r = semaphore_timedwait(mach_semaphore, ts);
}
return (r == KERN_SUCCESS);
}
void QMutexPrivate::wakeUp()
{
semaphore_signal(mach_semaphore);
}
QT_END_NAMESPACE
#endif //QT_NO_THREAD

View File

@ -57,50 +57,80 @@
#include <QtCore/qglobal.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qmutex.h>
#include <QtCore/qatomic.h>
#if defined(Q_OS_MAC)
# include <mach/semaphore.h>
#endif
#if defined(Q_OS_SYMBIAN)
# include <e32std.h>
#endif
QT_BEGIN_NAMESPACE
class QMutexPrivate : public QMutexData {
class QMutexPrivate {
public:
QMutexPrivate(QMutex::RecursionMode mode);
~QMutexPrivate();
QMutexPrivate(QMutex::RecursionMode mode = QMutex::NonRecursive);
bool wait(int timeout = -1);
void wakeUp();
// 1ms = 1000000ns
enum { MaximumSpinTimeThreshold = 1000000 };
volatile qint64 maximumSpinTime;
volatile qint64 averageWaitTime;
Qt::HANDLE owner;
uint count;
#if !defined(Q_OS_LINUX)
// Conrol the lifetime of the privates
QAtomicInt refCount;
int id;
bool ref() {
Q_ASSERT(refCount >= 0);
int c;
do {
c = refCount;
if (c == 0)
return false;
} while (!refCount.testAndSetRelaxed(c, c + 1));
Q_ASSERT(refCount >= 0);
return true;
}
void deref() {
Q_ASSERT(refCount >=0);
if (!refCount.deref())
release();
Q_ASSERT(refCount >=0);
}
void release();
static QMutexPrivate *allocate();
QAtomicInt waiters; //number of thread waiting
QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out
enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads)
void derefWaiters(int value);
#endif
// handle recursive mutex
bool recursive;
//platform specific stuff
#if defined(Q_OS_MAC)
semaphore_t mach_semaphore;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN)
volatile bool wakeup;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX)
bool wakeup;
pthread_mutex_t mutex;
pthread_cond_t cond;
#elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
HANDLE event;
#elif defined(Q_OS_SYMBIAN)
RSemaphore lock;
#endif
};
inline QMutexData::QMutexData(QMutex::RecursionMode mode)
: recursive(mode == QMutex::Recursive)
{}
class QRecursiveMutexPrivate : public QMutexPrivate
{
public:
QRecursiveMutexPrivate()
: QMutexPrivate(QMutex::Recursive), owner(0), count(0) {}
Qt::HANDLE owner;
uint count;
QMutex mutex;
inline QMutexData::~QMutexData() {}
bool lock(int timeout);
void unlock();
};
QT_END_NAMESPACE

View File

@ -46,142 +46,35 @@
#ifndef QT_NO_THREAD
#include "qatomic.h"
#include "qmutex_p.h"
#include <errno.h>
#if defined(Q_OS_VXWORKS) && defined(wakeup)
#undef wakeup
#endif
#if defined(Q_OS_MAC)
# include <mach/mach.h>
# include <mach/task.h>
#elif defined(Q_OS_LINUX)
# include <linux/futex.h>
# include <sys/syscall.h>
# include <unistd.h>
# include <QtCore/qelapsedtimer.h>
#endif
QT_BEGIN_NAMESPACE
#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX)
static void report_error(int code, const char *where, const char *what)
{
if (code != 0)
qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code)));
}
#endif
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0)
: recursive(mode == QMutex::Recursive), wakeup(false)
{
#if defined(Q_OS_MAC)
kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0);
if (r != KERN_SUCCESS)
qWarning("QMutex: failed to create semaphore, error %d", r);
#elif !defined(Q_OS_LINUX)
wakeup = false;
report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init");
report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init");
#endif
}
QMutexPrivate::~QMutexPrivate()
{
#if defined(Q_OS_MAC)
kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore);
if (r != KERN_SUCCESS)
qWarning("QMutex: failed to destroy semaphore, error %d", r);
#elif !defined(Q_OS_LINUX)
report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy");
report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy");
#endif
}
#if defined(Q_OS_MAC)
bool QMutexPrivate::wait(int timeout)
{
if (contenders.fetchAndAddAcquire(1) == 0) {
// lock acquired without waiting
return true;
}
kern_return_t r;
if (timeout < 0) {
do {
r = semaphore_wait(mach_semaphore);
} while (r == KERN_ABORTED);
if (r != KERN_SUCCESS)
qWarning("QMutex: infinite wait failed, error %d", r);
} else {
mach_timespec_t ts;
ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
ts.tv_sec = (timeout / 1000);
r = semaphore_timedwait(mach_semaphore, ts);
}
contenders.deref();
return r == KERN_SUCCESS;
}
void QMutexPrivate::wakeUp()
{
semaphore_signal(mach_semaphore);
}
#elif defined(Q_OS_LINUX)
static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2)
{
return syscall(SYS_futex, addr, op, val, timeout, addr2, val2);
}
bool QMutexPrivate::wait(int timeout)
{
struct timespec ts, *pts = 0;
QElapsedTimer timer;
if (timeout >= 0) {
ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
ts.tv_sec = (timeout / 1000);
pts = &ts;
timer.start();
}
while (contenders.fetchAndStoreAcquire(2) > 0) {
int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0);
if (r != 0 && errno == ETIMEDOUT)
return false;
if (pts) {
// recalculate the timeout
qint64 xtimeout = timeout * 1000 * 1000;
xtimeout -= timer.nsecsElapsed();
if (xtimeout < 0) {
// timer expired after we returned
return false;
}
ts.tv_sec = timeout / Q_INT64_C(1000) / 1000 / 1000;
ts.tv_nsec = timeout % (Q_INT64_C(1000) * 1000 * 1000);
}
}
return true;
}
void QMutexPrivate::wakeUp()
{
(void) contenders.fetchAndStoreRelease(0);
(void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0);
}
#else // !Q_OS_MAC && !Q_OS_LINUX
bool QMutexPrivate::wait(int timeout)
{
if (contenders.fetchAndAddAcquire(1) == 0) {
// lock acquired without waiting
return true;
}
report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock");
int errorCode = 0;
while (!wakeup) {
@ -190,12 +83,10 @@ bool QMutexPrivate::wait(int timeout)
} else {
struct timeval tv;
gettimeofday(&tv, 0);
timespec ti;
ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000;
ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
ti.tv_nsec %= 1000000000;
errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
}
if (errorCode) {
@ -207,10 +98,10 @@ bool QMutexPrivate::wait(int timeout)
report_error(errorCode, "QMutex::lock()", "cv wait");
}
}
bool ret = wakeup;
wakeup = false;
report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock");
contenders.deref();
return errorCode == 0;
return ret;
}
void QMutexPrivate::wakeUp()
@ -221,7 +112,6 @@ void QMutexPrivate::wakeUp()
report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock");
}
#endif // !Q_OS_MAC && !Q_OS_LINUX
QT_END_NAMESPACE

View File

@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0)
: recursive(mode)
{
event = CreateEvent(0, FALSE, FALSE, 0);
if (!event)
@ -60,13 +60,7 @@ QMutexPrivate::~QMutexPrivate()
bool QMutexPrivate::wait(int timeout)
{
if (contenders.fetchAndAddAcquire(1) == 0) {
// lock acquired without waiting
return true;
}
bool returnValue = (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0);
contenders.deref();
return returnValue;
return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0);
}
void QMutexPrivate::wakeUp()

View File

@ -79,8 +79,8 @@ public:
void relock()
{
if (!locked) {
if (mtx1) mtx1->lockInline();
if (mtx2) mtx2->lockInline();
if (mtx1) mtx1->lock();
if (mtx2) mtx2->lock();
locked = true;
}
}
@ -88,8 +88,8 @@ public:
void unlock()
{
if (locked) {
if (mtx1) mtx1->unlockInline();
if (mtx2) mtx2->unlockInline();
if (mtx1) mtx1->unlock();
if (mtx2) mtx2->unlock();
locked = false;
}
}
@ -100,10 +100,10 @@ public:
if (mtx1 == mtx2)
return false;
if (mtx1 < mtx2) {
mtx2->lockInline();
mtx2->lock();
return true;
}
if (!mtx2->tryLockInline()) {
if (!mtx2->tryLock()) {
mtx1->unlock();
mtx2->lock();
mtx1->lock();

View File

@ -146,7 +146,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
{
if (! mutex)
return false;
if (mutex->d->recursive) {
if (mutex->isRecursive()) {
qWarning("QWaitCondition: cannot wait on recursive mutexes");
return false;
}

View File

@ -164,7 +164,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
{
if (!mutex)
return false;
if (mutex->d->recursive) {
if (mutex->isRecursive()) {
qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes");
return false;
}

View File

@ -24,8 +24,7 @@ SOURCES += thread/qatomic.cpp \
thread/qthread.cpp \
thread/qthreadstorage.cpp
unix:!symbian:SOURCES += thread/qmutex_unix.cpp \
thread/qthread_unix.cpp \
unix:!symbian:SOURCES += thread/qthread_unix.cpp \
thread/qwaitcondition_unix.cpp
symbian:SOURCES += thread/qmutex_symbian.cpp \
@ -39,3 +38,9 @@ win32:SOURCES += thread/qmutex_win.cpp \
integrity:SOURCES += thread/qmutex_unix.cpp \
thread/qthread_unix.cpp \
thread/qwaitcondition_unix.cpp
unix: {
macx-* { SOURCES += thread/qmutex_mac.cpp }
else:linux-* { SOURCES += thread/qmutex_linux.cpp }
else { SOURCES += thread/qmutex_unix.cpp }
}

View File

@ -904,7 +904,7 @@ QByteArray &QByteArray::operator=(const char *str)
x = const_cast<Data *>(&shared_empty.ba);
} else {
int len = qstrlen(str);
if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1))
if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1))
realloc(len);
x = d;
memcpy(x->data(), str, len + 1); // include null terminator
@ -1432,9 +1432,10 @@ void QByteArray::resize(int size)
x->data()[size] = '\0';
d = x;
} else {
if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1))
if (d->ref != 1 || size > int(d->alloc)
|| (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(qAllocMore(size, sizeof(Data)));
if (d->alloc >= size) {
if (int(d->alloc) >= size) {
d->size = size;
d->data()[size] = '\0';
}
@ -1563,7 +1564,7 @@ QByteArray &QByteArray::prepend(const char *str)
QByteArray &QByteArray::prepend(const char *str, int len)
{
if (str) {
if (d->ref != 1 || d->size + len > d->alloc)
if (d->ref != 1 || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memmove(d->data()+len, d->data(), d->size);
memcpy(d->data(), str, len);
@ -1581,7 +1582,7 @@ QByteArray &QByteArray::prepend(const char *str, int len)
QByteArray &QByteArray::prepend(char ch)
{
if (d->ref != 1 || d->size + 1 > d->alloc)
if (d->ref != 1 || d->size + 1 > int(d->alloc))
realloc(qAllocMore(d->size + 1, sizeof(Data)));
memmove(d->data()+1, d->data(), d->size);
d->data()[0] = ch;
@ -1619,7 +1620,7 @@ QByteArray &QByteArray::append(const QByteArray &ba)
if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) {
*this = ba;
} else if (ba.d != &shared_null.ba) {
if (d->ref != 1 || d->size + ba.d->size > d->alloc)
if (d->ref != 1 || d->size + ba.d->size > int(d->alloc))
realloc(qAllocMore(d->size + ba.d->size, sizeof(Data)));
memcpy(d->data() + d->size, ba.d->data(), ba.d->size);
d->size += ba.d->size;
@ -1653,7 +1654,7 @@ QByteArray& QByteArray::append(const char *str)
{
if (str) {
int len = qstrlen(str);
if (d->ref != 1 || d->size + len > d->alloc)
if (d->ref != 1 || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len + 1); // include null terminator
d->size += len;
@ -1678,7 +1679,7 @@ QByteArray &QByteArray::append(const char *str, int len)
if (len < 0)
len = qstrlen(str);
if (str && len) {
if (d->ref != 1 || d->size + len > d->alloc)
if (d->ref != 1 || d->size + len > int(d->alloc))
realloc(qAllocMore(d->size + len, sizeof(Data)));
memcpy(d->data() + d->size, str, len); // include null terminator
d->size += len;
@ -1695,7 +1696,7 @@ QByteArray &QByteArray::append(const char *str, int len)
QByteArray& QByteArray::append(char ch)
{
if (d->ref != 1 || d->size + 1 > d->alloc)
if (d->ref != 1 || d->size + 1 > int(d->alloc))
realloc(qAllocMore(d->size + 1, sizeof(Data)));
d->data()[d->size++] = ch;
d->data()[d->size] = '\0';
@ -2204,7 +2205,7 @@ QByteArray QByteArray::repeated(int times) const
QByteArray result;
result.reserve(resultSize);
if (result.d->alloc != resultSize)
if (int(result.d->alloc) != resultSize)
return QByteArray(); // not enough memory
memcpy(result.d->data(), d->data(), d->size);

View File

@ -133,10 +133,10 @@ struct QByteArrayData
inline const char *data() const { return d + sizeof(qptrdiff) + offset; }
};
template<int n> struct QConstByteArrayData
template<int N> struct QConstByteArrayData
{
const QByteArrayData ba;
const char data[n];
const char data[N + 1];
};
template<int N> struct QConstByteArrayDataPtr
@ -146,10 +146,10 @@ template<int N> struct QConstByteArrayDataPtr
#if defined(Q_COMPILER_LAMBDA)
# define QByteArrayLiteral(str) ([]() { \
enum { Size = sizeof(str) }; \
# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr<sizeof(str) - 1> { \
enum { Size = sizeof(str) - 1 }; \
static const QConstByteArrayData<Size> qbytearray_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \
QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
return holder; }())
@ -160,9 +160,9 @@ template<int N> struct QConstByteArrayDataPtr
# define QByteArrayLiteral(str) \
__extension__ ({ \
enum { Size = sizeof(str) }; \
enum { Size = sizeof(str) - 1 }; \
static const QConstByteArrayData<Size> qbytearray_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \
QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \
holder; })
#endif
@ -439,10 +439,10 @@ inline int QByteArray::capacity() const
{ return d->alloc; }
inline void QByteArray::reserve(int asize)
{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; }
{ if (d->ref != 1 || asize > int(d->alloc)) realloc(asize); d->capacityReserved = true; }
inline void QByteArray::squeeze()
{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; }
{ if (d->size < int(d->alloc)) realloc(d->size); d->capacityReserved = false; }
class Q_CORE_EXPORT QByteRef {
QByteArray &a;

View File

@ -317,8 +317,6 @@ QT_BEGIN_NAMESPACE
\value Vertical
\value Wide
\omitvalue Single
\sa decomposition()
*/
@ -382,12 +380,6 @@ QT_BEGIN_NAMESPACE
\value ByteOrderSwapped
\value ParagraphSeparator
\value LineSeparator
\omitvalue null
\omitvalue replacement
\omitvalue byteOrderMark
\omitvalue byteOrderSwapped
\omitvalue nbsp
*/
/*!
@ -957,7 +949,7 @@ QString QChar::decomposition(uint ucs4)
/*!
Returns the tag defining the composition of the character. Returns
QChar::Single if no decomposition exists.
QChar::NoDecomposition if no decomposition exists.
*/
QChar::Decomposition QChar::decompositionTag() const
{
@ -967,7 +959,7 @@ QChar::Decomposition QChar::decompositionTag() const
/*!
\overload
Returns the tag defining the composition of the UCS-4-encoded character
specified by \a ucs4. Returns QChar::Single if no decomposition exists.
specified by \a ucs4. Returns QChar::NoDecomposition if no decomposition exists.
*/
QChar::Decomposition QChar::decompositionTag(uint ucs4)
{
@ -1232,7 +1224,6 @@ ushort QChar::toCaseFolded(ushort ucs2)
return ucs2 + qGetProp(ucs2)->caseFoldDiff;
}
/*!
\fn char QChar::toLatin1() const

View File

@ -0,0 +1,67 @@
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qfreelist_p.h"
QT_BEGIN_NAMESPACE
// default sizes and offsets (no need to define these when customizing)
enum {
Offset0 = 0x00000000,
Offset1 = 0x00008000,
Offset2 = 0x00080000,
Offset3 = 0x00800000,
Size0 = Offset1 - Offset0,
Size1 = Offset2 - Offset1,
Size2 = Offset3 - Offset2,
Size3 = QFreeListDefaultConstants::MaxIndex - Offset3
};
const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = {
Size0,
Size1,
Size2,
Size3
};
QT_END_NAMESPACE

View File

@ -0,0 +1,294 @@
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QFREELIST_P_H
#define QFREELIST_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/qatomic.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Core)
/*! \internal
Element in a QFreeList. ConstReferenceType and ReferenceType are used as
the return values for QFreeList::at() and QFreeList::operator[](). Contains
the real data storage (_t) and the id of the next free element (next).
Note: the t() functions should be used to access the data, not _t.
*/
template <typename T>
struct QFreeListElement
{
typedef const T &ConstReferenceType;
typedef T &ReferenceType;
T _t;
int next;
inline ConstReferenceType t() const { return _t; }
inline ReferenceType t() { return _t; }
};
/*! \internal
Element in a QFreeList without a paylout. ConstReferenceType and
ReferenceType are void, the t() functions return void and are empty.
*/
template <>
struct QFreeListElement<void>
{
typedef void ConstReferenceType;
typedef void ReferenceType;
int next;
inline void t() const { }
inline void t() { }
};
/*! \internal
Defines default constants used by QFreeList:
- The initial value returned by QFreeList::next() is zero.
- QFreeList allows for up to 16777216 elements in QFreeList and uses the top
8 bits to store a serial counter for ABA protection.
- QFreeList will make a maximum of 4 allocations (blocks), with each
successive block larger than the previous.
- Sizes static int[] array to define the size of each block.
It is possible to define your own constants struct/class and give this to
QFreeList to customize/tune the behavior.
*/
struct Q_AUTOTEST_EXPORT QFreeListDefaultConstants
{
// used by QFreeList, make sure to define all of when customizing
enum {
InitialNextValue = 0,
IndexMask = 0x00ffffff,
SerialMask = ~IndexMask & ~0x80000000,
SerialCounter = IndexMask + 1,
MaxIndex = IndexMask,
BlockCount = 4,
};
static const int Sizes[BlockCount];
};
/*! \internal
This is a generic implementation of a lock-free free list. Use next() to
get the next free entry in the list, and release(id) when done with the id.
This version is templated and allows having a payload of type T which can
be accessed using the id returned by next(). The payload is allocated and
deallocated automatically by the free list, but *NOT* when calling
next()/release(). Initialization should be done by code needing it after
next() returns. Likewise, cleanup() should happen before calling release().
It is possible to have use 'void' as the payload type, in which case the
free list only contains indexes to the next free entry.
The ConstantsType type defaults to QFreeListDefaultConstants above. You can
define your custom ConstantsType, see above for details on what needs to be
available.
*/
template <typename T, typename ConstantsType = QFreeListDefaultConstants>
class QFreeList
{
typedef T ValueType;
typedef QFreeListElement<T> ElementType;
typedef typename ElementType::ConstReferenceType ConstReferenceType;
typedef typename ElementType::ReferenceType ReferenceType;
// return which block the index \a x falls in, and modify \a x to be the index into that block
static inline int blockfor(int &x)
{
for (int i = 0; i < ConstantsType::BlockCount; ++i) {
int size = ConstantsType::Sizes[i];
if (x < size)
return i;
x -= size;
}
Q_ASSERT(false);
return -1;
}
// allocate a block of the given \a size, initialized starting with the given \a offset
static inline ElementType *allocate(int offset, int size)
{
// qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset);
ElementType *v = new ElementType[size];
for (int i = 0; i < size; ++i)
v[i].next = offset + i + 1;
return v;
}
// take the current serial number from \a o, increment it, and store it in \a n
static inline int incrementserial(int o, int n)
{
return (n & ConstantsType::IndexMask) | ((o + ConstantsType::SerialCounter) & ConstantsType::SerialMask);
}
// the blocks
QAtomicPointer<ElementType> _v[ConstantsType::BlockCount];
// the next free id
QAtomicInt _next;
// QFreeList is not copyable
Q_DISABLE_COPY(QFreeList)
public:
inline QFreeList();
inline ~QFreeList();
// returns the payload for the given index \a x
inline ConstReferenceType at(int x) const;
inline ReferenceType operator[](int x);
/*
Return the next free id. Use this id to access the payload (see above).
Call release(id) when done using the id.
*/
inline int next();
inline void release(int id);
};
template <typename T, typename ConstantsType>
inline QFreeList<T, ConstantsType>::QFreeList()
: _next(ConstantsType::InitialNextValue)
{ }
template <typename T, typename ConstantsType>
inline QFreeList<T, ConstantsType>::~QFreeList()
{
for (int i = 0; i < ConstantsType::BlockCount; ++i)
delete [] static_cast<ElementType *>(_v[i]);
}
template <typename T, typename ConstantsType>
inline typename QFreeList<T, ConstantsType>::ConstReferenceType QFreeList<T, ConstantsType>::at(int x) const
{
const int block = blockfor(x);
return _v[block][x].t();
}
template <typename T, typename ConstantsType>
inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, ConstantsType>::operator[](int x)
{
const int block = blockfor(x);
return _v[block][x].t();
}
template <typename T, typename ConstantsType>
inline int QFreeList<T, ConstantsType>::next()
{
int id, newid, at;
ElementType *v;
do {
id = _next; // .loadAqcuire();
at = id & ConstantsType::IndexMask;
const int block = blockfor(at);
v = _v[block];
if (!v) {
v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]);
if (!_v[block].testAndSetRelease(0, v)) {
// race with another thread lost
delete [] v;
v = _v[block];
Q_ASSERT(v != 0);
}
}
newid = v[at].next | (id & ~ConstantsType::IndexMask);
} while (!_next.testAndSetRelease(id, newid));
// qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)",
// id & ConstantsType::IndexMask,
// newid & ConstantsType::IndexMask,
// (newid & ~ConstantsType::IndexMask) >> 24);
return id & ConstantsType::IndexMask;
}
template <typename T, typename ConstantsType>
inline void QFreeList<T, ConstantsType>::release(int id)
{
int at = id & ConstantsType::IndexMask;
const int block = blockfor(at);
ElementType *v = _v[block];
int x, newid;
do {
x = _next; // .loadAcquire();
v[at].next = x & ConstantsType::IndexMask;
newid = incrementserial(x, id);
} while (!_next.testAndSetRelease(x, newid));
// qDebug("QFreeList::release(%d): _next now %d (was %d), serial %d",
// id & ConstantsType::IndexMask,
// newid & ConstantsType::IndexMask,
// x & ConstantsType::IndexMask,
// (newid & ~ConstantsType::IndexMask) >> 24);
}
QT_END_NAMESPACE
QT_END_HEADER
#endif // QFREELIST_P_H

View File

@ -102,7 +102,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch)
return QChar::mirroredChar(ch);
}
void *HB_Library_Resolve(const char *library, int version, const char *symbol)
void (*HB_Library_Resolve(const char *library, int version, const char *symbol))()
{
#ifdef QT_NO_LIBRARY
return 0;

View File

@ -279,6 +279,9 @@ namespace std {
QT_BEGIN_NAMESPACE
#endif
template<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_MOVABLE_TYPE);
template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
QT_END_HEADER

View File

@ -1267,10 +1267,10 @@ void QString::resize(int size)
QString::free(d);
d = x;
} else {
if (d->ref != 1 || size > d->alloc ||
(!d->capacityReserved && size < d->size && size < d->alloc >> 1))
if (d->ref != 1 || size > int(d->alloc) ||
(!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1))
realloc(grow(size));
if (d->alloc >= size) {
if (int(d->alloc) >= size) {
d->size = size;
d->data()[size] = '\0';
}
@ -1560,7 +1560,7 @@ QString &QString::append(const QString &str)
if (d == &shared_null.str) {
operator=(str);
} else {
if (d->ref != 1 || d->size + str.d->size > d->alloc)
if (d->ref != 1 || d->size + str.d->size > int(d->alloc))
realloc(grow(d->size + str.d->size));
memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar));
d->size += str.d->size;
@ -1580,7 +1580,7 @@ QString &QString::append(const QLatin1String &str)
const uchar *s = (const uchar *)str.latin1();
if (s) {
int len = qstrlen((char *)s);
if (d->ref != 1 || d->size + len > d->alloc)
if (d->ref != 1 || d->size + len > int(d->alloc))
realloc(grow(d->size + len));
ushort *i = d->data() + d->size;
while ((*i++ = *s++))
@ -1623,7 +1623,7 @@ QString &QString::append(const QLatin1String &str)
*/
QString &QString::append(QChar ch)
{
if (d->ref != 1 || d->size + 1 > d->alloc)
if (d->ref != 1 || d->size + 1 > int(d->alloc))
realloc(grow(d->size + 1));
d->data()[d->size++] = ch.unicode();
d->data()[d->size] = '\0';
@ -3550,8 +3550,8 @@ static QByteArray toLatin1_helper(const QChar *data, int length)
const __m128i questionMark = _mm_set1_epi16('?');
// SSE has no compare instruction for unsigned comparison.
// The variables must be shiffted + 0x8000 to be compared
const __m128i signedBitOffset = _mm_set1_epi16(0x8000);
const __m128i thresholdMask = _mm_set1_epi16(0xff + 0x8000);
const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000));
const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000));
for (int i = 0; i < chunkCount; ++i) {
__m128i chunk1 = _mm_loadu_si128((__m128i*)src); // load
src += 8;
@ -6152,7 +6152,7 @@ QString QString::repeated(int times) const
QString result;
result.reserve(resultSize);
if (result.d->alloc != resultSize)
if (int(result.d->alloc) != resultSize)
return QString(); // not enough memory
memcpy(result.d->data(), d->data(), d->size * sizeof(ushort));

View File

@ -97,36 +97,43 @@ template<int N> struct QConstStringDataPtr
};
#if defined(Q_COMPILER_UNICODE_STRINGS)
template<int n> struct QConstStringData
template<int N> struct QConstStringData
{
const QStringData str;
const char16_t data[n];
const char16_t data[N + 1];
};
#define QT_QSTRING_UNICODE_MARKER u""
#define QT_UNICODE_LITERAL_II(str) u"" str
#elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536)
// wchar_t is 2 bytes
template<int n> struct QConstStringData
template<int N> struct QConstStringData
{
const QStringData str;
const wchar_t data[n];
const wchar_t data[N + 1];
};
#define QT_QSTRING_UNICODE_MARKER L""
#if defined(Q_CC_MSVC)
# define QT_UNICODE_LITERAL_II(str) L##str
#else
# define QT_UNICODE_LITERAL_II(str) L"" str
#endif
#else
template<int n> struct QConstStringData
template<int N> struct QConstStringData
{
const QStringData str;
const ushort data[n];
const ushort data[N + 1];
};
#endif
#if defined(QT_QSTRING_UNICODE_MARKER)
#if defined(QT_UNICODE_LITERAL_II)
# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str)
# if defined(Q_COMPILER_LAMBDA)
# define QStringLiteral(str) ([]() { \
enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \
# define QStringLiteral(str) ([]() -> QConstStringDataPtr<sizeof(QT_UNICODE_LITERAL(str))/2 - 1> { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QConstStringData<Size> qstring_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \
QConstStringDataPtr<Size> holder = { &qstring_literal }; \
return holder; }())
@ -137,9 +144,9 @@ template<int n> struct QConstStringData
# define QStringLiteral(str) \
__extension__ ({ \
enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QConstStringData<Size> qstring_literal = \
{ { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \
{ { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \
QConstStringDataPtr<Size> holder = { &qstring_literal }; \
holder; })
# endif

View File

@ -108,13 +108,12 @@ QT_BEGIN_NAMESPACE
*/
/*! \internal
Note: The len contains the ending \0
*/
void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out)
{
#ifndef QT_NO_TEXTCODEC
if (QString::codecForCStrings && len) {
QString tmp = QString::fromAscii(a, len > 0 ? len - 1 : -1);
QString tmp = QString::fromAscii(a, len > 0 ? len : -1);
memcpy(out, reinterpret_cast<const char *>(tmp.constData()), sizeof(QChar) * tmp.size());
out += tmp.length();
return;
@ -126,7 +125,7 @@ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out
while (*a)
*out++ = QLatin1Char(*a++);
} else {
for (int i = 0; i < len - 1; ++i)
for (int i = 0; i < len; ++i)
*out++ = QLatin1Char(a[i]);
}
}

View File

@ -294,7 +294,7 @@ template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable
#ifndef QT_NO_CAST_FROM_ASCII
static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
{
QAbstractConcatenable::convertFromAscii(a, N, out);
QAbstractConcatenable::convertFromAscii(a, N - 1, out);
}
#endif
static inline void appendTo(const char a[N], char *&out)
@ -313,7 +313,7 @@ template <int N> struct QConcatenable<const char[N]> : private QAbstractConcaten
#ifndef QT_NO_CAST_FROM_ASCII
static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out)
{
QAbstractConcatenable::convertFromAscii(a, N, out);
QAbstractConcatenable::convertFromAscii(a, N - 1, out);
}
#endif
static inline void appendTo(const char a[N], char *&out)
@ -349,10 +349,9 @@ template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
enum { ExactSize = false };
static int size(const QByteArray &ba) { return ba.size(); }
#ifndef QT_NO_CAST_FROM_ASCII
static inline void appendTo(const QByteArray &ba, QChar *&out)
static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out)
{
// adding 1 because convertFromAscii expects the size including the null-termination
QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out);
QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out);
}
#endif
static inline void appendTo(const QByteArray &ba, char *&out)
@ -364,6 +363,26 @@ template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
}
};
template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbstractConcatenable
{
typedef QConstByteArrayDataPtr<N> type;
typedef QByteArray ConvertTo;
enum { ExactSize = false };
static int size(const type &) { return N; }
#ifndef QT_NO_CAST_FROM_ASCII
static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out)
{
QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out);
}
#endif
static inline void appendTo(const type &ba, char *&out)
{
const char *a = ba.ptr->data;
while (*a)
*out++ = *a++;
}
};
namespace QtStringBuilder {
template <typename A, typename B> struct ConvertToTypeHelper
{ typedef A ConvertTo; };

View File

@ -13,6 +13,7 @@ HEADERS += \
tools/qdatetime.h \
tools/qdatetime_p.h \
tools/qeasingcurve.h \
tools/qfreelist_p.h \
tools/qhash.h \
tools/qline.h \
tools/qlinkedlist.h \
@ -61,6 +62,7 @@ SOURCES += \
tools/qdatetime.cpp \
tools/qeasingcurve.cpp \
tools/qelapsedtimer.cpp \
tools/qfreelist.cpp \
tools/qhash.cpp \
tools/qline.cpp \
tools/qlinkedlist.cpp \

View File

@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
void *qdbus_resolve_me(const char *name);
void (*qdbus_resolve_me(const char *name))();
#if !defined QT_LINKED_LIBDBUS
@ -95,20 +95,19 @@ bool qdbus_loadLibDBus()
return false;
}
void *qdbus_resolve_conditionally(const char *name)
void (*qdbus_resolve_conditionally(const char *name))()
{
if (qdbus_loadLibDBus())
return qdbus_libdbus->resolve(name);
return 0;
}
void *qdbus_resolve_me(const char *name)
void (*qdbus_resolve_me(const char *name))()
{
void *ptr = 0;
if (!qdbus_loadLibDBus())
qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name);
ptr = qdbus_libdbus->resolve(name);
QFunctionPointer ptr = qdbus_libdbus->resolve(name);
if (!ptr)
qFatal("Cannot resolve '%s' in your libdbus-1.", name);

View File

@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE
#if !defined QT_LINKED_LIBDBUS
void *qdbus_resolve_conditionally(const char *name); // doesn't print a warning
void *qdbus_resolve_me(const char *name); // prints a warning
void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning
void (*qdbus_resolve_me(const char *name))(); // prints a warning
bool qdbus_loadLibDBus();
# define DEFINEFUNC(ret, func, args, argcall, funcret) \

View File

@ -125,6 +125,11 @@ private:
MethodScriptable = 0x40
};
enum MetaObjectFlags {
DynamicMetaObject = 0x01,
RequiresVariantMetaObject = 0x02
};
QMap<QByteArray, Method> methods;
QMap<QByteArray, Property> properties;
@ -152,6 +157,8 @@ struct QDBusMetaObjectPrivate
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData; // since revision 2
int flags; // since revision 3
// this is specific for QDBusMetaObject:
int propertyDBusData;
@ -416,7 +423,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int));
QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
header->revision = 1;
header->revision = 3;
header->className = 0;
header->classInfoCount = 0;
header->classInfoData = 0;
@ -426,6 +433,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
header->propertyData = header->methodData + header->methodCount * 5;
header->enumeratorCount = 0;
header->enumeratorData = 0;
header->constructorCount = 0;
header->constructorData = 0;
header->flags = RequiresVariantMetaObject;
header->propertyDBusData = header->propertyData + header->propertyCount * 3;
header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty;

View File

@ -97,8 +97,10 @@ static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf)
const int BMP_OLD = 12; // old Windows/OS2 BMP size
const int BMP_WIN = 40; // new Windows BMP size
const int BMP_WIN = 40; // Windows BMP v3 size
const int BMP_OS2 = 64; // new OS/2 BMP size
const int BMP_WIN4 = 108; // Windows BMP v4 size
const int BMP_WIN5 = 124; // Windows BMP v5 size
const int BMP_RGB = 0; // no compression
const int BMP_RLE8 = 1; // run-length encoded, 8 bits
@ -109,7 +111,7 @@ const int BMP_BITFIELDS = 3; // RGB values encoded in dat
static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi)
{
s >> bi.biSize;
if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2) {
if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) {
s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
s >> bi.biCompression >> bi.biSizeImage;
s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
@ -255,7 +257,57 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
image.setDotsPerMeterY(bi.biYPelsPerMeter);
if (!d->isSequential())
d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap
d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
Q_ASSERT(ncols == 0);
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
return false;
if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
return false;
// Read BMP v4+ header
if (bi.biSize >= BMP_WIN4) {
int alpha_mask = 0;
int CSType = 0;
int gamma_red = 0;
int gamma_green = 0;
int gamma_blue = 0;
int endpoints[9];
if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask))
return false;
if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType))
return false;
if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints))
return false;
if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red))
return false;
if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green))
return false;
if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue))
return false;
if (bi.biSize == BMP_WIN5) {
qint32 intent = 0;
qint32 profileData = 0;
qint32 profileSize = 0;
qint32 reserved = 0;
if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent))
return false;
if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData))
return false;
if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize))
return false;
if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0)
return false;
}
}
}
if (ncols > 0) { // read color table
uchar rgb[4];
@ -268,12 +320,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int
return false;
}
} else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
return false;
if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
return false;
if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
return false;
red_shift = calc_shift(red_mask);
red_scale = 256 / ((red_mask >> red_shift) + 1);
green_shift = calc_shift(green_mask);

View File

@ -236,14 +236,14 @@ bool QTiffHandler::read(QImage *image)
}
} else {
// create the color table
uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
if (!redTable || !greenTable || !blueTable) {
uint16 *redTable = 0;
uint16 *greenTable = 0;
uint16 *blueTable = 0;
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
TIFFClose(tiff);
return false;
}
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
if (!redTable || !greenTable || !blueTable) {
TIFFClose(tiff);
return false;
}
@ -500,6 +500,9 @@ bool QTiffHandler::write(const QImage &image)
uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
if (!redTable || !greenTable || !blueTable) {
qFree(redTable);
qFree(greenTable);
qFree(blueTable);
TIFFClose(tiff);
return false;
}

View File

@ -55,6 +55,20 @@ QT_BEGIN_NAMESPACE
\since 4.6
\ingroup painting-3D
The QMatrix4x4 class in general is treated as a row-major matrix, in that the
constructors and operator() functions take data in row-major format, as is
familiar in C-style usage.
Internally the data is stored as column-major format, so as to be optimal for
passing to OpenGL functions, which expect column-major data.
When using these functions be aware that they return data in \bold{column-major}
format:
\list
\o data()
\o constData()
\endlist
\sa QVector3D, QGenericMatrix
*/
@ -1725,6 +1739,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const
\fn const qreal *QMatrix4x4::data() const
Returns a constant pointer to the raw data of this matrix.
This raw data is stored in column-major format.
\sa constData()
*/
@ -1733,6 +1748,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const
\fn const qreal *QMatrix4x4::constData() const
Returns a constant pointer to the raw data of this matrix.
This raw data is stored in column-major format.
\sa data()
*/

View File

@ -3005,7 +3005,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
ensureState();
QFontEngine *fontEngine = textItem->fontEngine();
if (!supportsTransformations(fontEngine)) {
if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) {
drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
fontEngine);
} else {
@ -3355,10 +3355,7 @@ bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransfo
#endif
return true;
if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
return true;
return false;
return !shouldDrawCachedGlyphs(pixelSize, m);
}
/*!

View File

@ -53,6 +53,10 @@
QT_BEGIN_NAMESPACE
#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
# define QT_MAX_CACHED_GLYPH_SIZE 64
#endif
/*******************************************************************************
*
* class QVectorPath
@ -1096,4 +1100,10 @@ bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &
return false;
}
bool QPaintEngineEx::shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const
{
return (pixelSize * pixelSize * qAbs(m.determinant())) <
QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
}
QT_END_NAMESPACE

View File

@ -228,6 +228,7 @@ public:
};
virtual uint flags() const {return 0;}
virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const;
virtual bool shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const;
protected:
QPaintEngineEx(QPaintEngineExPrivate &data);

View File

@ -155,6 +155,7 @@ public:
struct FaceId {
FaceId() : index(0), encoding(0) {}
QByteArray filename;
QByteArray uuid;
int index;
int encoding;
};
@ -303,7 +304,7 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId
inline uint qHash(const QFontEngine::FaceId &f)
{
return qHash((f.index << 16) + f.encoding) + qHash(f.filename);
return qHash((f.index << 16) + f.encoding) + qHash(f.filename + f.uuid);
}

View File

@ -139,7 +139,7 @@ QRawFont::QRawFont()
\note The referenced file must contain a TrueType or OpenType font.
*/
QRawFont::QRawFont(const QString &fileName,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
: d(new QRawFontPrivate)
{
@ -154,7 +154,7 @@ QRawFont::QRawFont(const QString &fileName,
\note The data must contain a TrueType or OpenType font.
*/
QRawFont::QRawFont(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
: d(new QRawFontPrivate)
{
@ -204,7 +204,7 @@ bool QRawFont::isValid() const
\sa loadFromData()
*/
void QRawFont::loadFromFile(const QString &fileName,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
QFile file(fileName);
@ -222,7 +222,7 @@ void QRawFont::loadFromFile(const QString &fileName,
\sa loadFromFile()
*/
void QRawFont::loadFromData(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
detach();

View File

@ -70,10 +70,10 @@ public:
QRawFont();
QRawFont(const QString &fileName,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting);
QRawFont(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting);
QRawFont(const QRawFont &other);
~QRawFont();
@ -117,11 +117,11 @@ public:
qreal unitsPerEm() const;
void loadFromFile(const QString &fileName,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference);
void loadFromData(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference);
bool supportsCharacter(quint32 ucs4) const;

View File

@ -45,6 +45,7 @@
#include "qrawfont_p.h"
#include "qfontengine_ft_p.h"
#include "quuid.h"
#if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)
# include "qfontengine_x11_p.h"
@ -87,6 +88,7 @@ public:
FaceId faceId;
faceId.filename = "";
faceId.index = 0;
faceId.uuid = QUuid::createUuid().toByteArray();
return init(faceId, true, Format_None, fontData);
}
@ -98,7 +100,7 @@ void QRawFontPrivate::platformCleanUp()
// Font engine handles all resources
}
void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize,
void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
Q_ASSERT(fontEngine == 0);

View File

@ -99,7 +99,7 @@ public:
void cleanUp();
void platformCleanUp();
void platformLoadFromData(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference);
static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); }

View File

@ -53,7 +53,7 @@ void QRawFontPrivate::platformCleanUp()
{
}
void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize,
void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
Q_ASSERT(fontEngine == 0);

View File

@ -1817,6 +1817,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
bool isGettingInput = !e->commitString().isEmpty()
|| e->preeditString() != cursor.block().layout()->preeditAreaText()
|| e->replacementLength() > 0;
bool forceSelectionChanged = false;
cursor.beginEditBlock();
if (isGettingInput) {
@ -1840,6 +1841,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor);
q->ensureCursorVisible();
repaintOldAndNewSelection(oldCursor);
forceSelectionChanged = true;
}
}
@ -1874,6 +1876,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
cursor_d->setX();
if (oldPreeditCursor != preeditCursor)
emit q->microFocusChanged();
selectionChanged(forceSelectionChanged);
}
QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const

View File

@ -1632,7 +1632,7 @@ bool QTextEngine::isRightToLeft() const
int QTextEngine::findItem(int strPos) const
{
itemize();
int left = 0;
int left = 1;
int right = layoutData->items.size()-1;
while(left <= right) {
int middle = ((right-left)/2)+left;

View File

@ -131,6 +131,69 @@ QT_BEGIN_NAMESPACE
\omitvalue Valid
*/
/*!
\fn void QIntValidator::topChanged(int top)
This signal is emitted after the top property changed.
\sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom()
\internal
*/
/*!
\fn void QIntValidator::bottomChanged(int bottom)
This signal is emitted after the bottom property changed.
\sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom()
\internal
*/
/*!
\fn void QDoubleValidator::topChanged(int top)
This signal is emitted after the top property changed.
\sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom()
\internal
*/
/*!
\fn void QDoubleValidator::bottomChanged(int bottom)
This signal is emitted after the bottom property changed.
\sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom()
\internal
*/
/*!
\fn void QDoubleValidator::decimalsChanged(int decimals)
This signal is emitted after the decimals property changed.
\internal
*/
/*!
\fn void QDoubleValidator::notationChanged(QDoubleValidator::Notation notation)
This signal is emitted after the notation property changed.
QDoubleValidator::Notation is not a registered metatype, so for queued connections,
you will have to register it with Q_DECLARE_METATYPE() and qRegisterMetaType().
\internal
*/
/*!
\fn void QRegExpValidator::regExpChanged(const QRegExp &regExp)
This signal is emitted after the regExp property changed.
\internal
*/
class QValidatorPrivate : public QObjectPrivate{
Q_DECLARE_PUBLIC(QValidator)
public:
@ -436,8 +499,15 @@ void QIntValidator::fixup(QString &input) const
void QIntValidator::setRange(int bottom, int top)
{
b = bottom;
t = top;
if (b != bottom) {
b = bottom;
emit bottomChanged(b);
}
if (t != top) {
t = top;
emit topChanged(t);
}
}
@ -710,9 +780,20 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL
void QDoubleValidator::setRange(double minimum, double maximum, int decimals)
{
b = minimum;
t = maximum;
dec = decimals;
if (b != minimum) {
b = minimum;
emit bottomChanged(b);
}
if (t != maximum) {
t = maximum;
emit topChanged(t);
}
if (dec != decimals) {
dec = decimals;
emit decimalsChanged(dec);
}
}
/*!
@ -771,7 +852,10 @@ void QDoubleValidator::setDecimals(int decimals)
void QDoubleValidator::setNotation(Notation newNotation)
{
Q_D(QDoubleValidator);
d->notation = newNotation;
if (d->notation != newNotation) {
d->notation = newNotation;
emit notationChanged(d->notation);
}
}
QDoubleValidator::Notation QDoubleValidator::notation() const
@ -915,7 +999,10 @@ QValidator::State QRegExpValidator::validate(QString &input, int& pos) const
void QRegExpValidator::setRegExp(const QRegExp& rx)
{
r = rx;
if (r != rx) {
r = rx;
emit regExpChanged(r);
}
}
#endif

View File

@ -96,8 +96,8 @@ private:
class Q_GUI_EXPORT QIntValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(int bottom READ bottom WRITE setBottom)
Q_PROPERTY(int top READ top WRITE setTop)
Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged)
Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged)
public:
explicit QIntValidator(QObject * parent = 0);
@ -113,7 +113,9 @@ public:
int bottom() const { return b; }
int top() const { return t; }
Q_SIGNALS:
void bottomChanged(int bottom);
void topChanged(int top);
#ifdef QT3_SUPPORT
public:
QT3_SUPPORT_CONSTRUCTOR QIntValidator(QObject * parent, const char *name);
@ -134,11 +136,11 @@ class QDoubleValidatorPrivate;
class Q_GUI_EXPORT QDoubleValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(double bottom READ bottom WRITE setBottom)
Q_PROPERTY(double top READ top WRITE setTop)
Q_PROPERTY(int decimals READ decimals WRITE setDecimals)
Q_PROPERTY(double bottom READ bottom WRITE setBottom NOTIFY bottomChanged)
Q_PROPERTY(double top READ top WRITE setTop NOTIFY topChanged)
Q_PROPERTY(int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged)
Q_ENUMS(Notation)
Q_PROPERTY(Notation notation READ notation WRITE setNotation)
Q_PROPERTY(Notation notation READ notation WRITE setNotation NOTIFY notationChanged)
public:
explicit QDoubleValidator(QObject * parent = 0);
@ -149,7 +151,6 @@ public:
StandardNotation,
ScientificNotation
};
QValidator::State validate(QString &, int &) const;
virtual void setRange(double bottom, double top, int decimals = 0);
@ -163,6 +164,12 @@ public:
int decimals() const { return dec; }
Notation notation() const;
Q_SIGNALS:
void bottomChanged(double bottom);
void topChanged(double top);
void decimalsChanged(int decimals);
void notationChanged(QDoubleValidator::Notation notation);
#ifdef QT3_SUPPORT
public:
QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(QObject * parent, const char *name);
@ -182,7 +189,7 @@ private:
class Q_GUI_EXPORT QRegExpValidator : public QValidator
{
Q_OBJECT
Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp)
Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp NOTIFY regExpChanged)
public:
explicit QRegExpValidator(QObject *parent = 0);
@ -194,6 +201,8 @@ public:
void setRegExp(const QRegExp& rx);
const QRegExp& regExp() const { return r; } // ### make inline for 5.0
Q_SIGNALS:
void regExpChanged(const QRegExp& regExp);
#ifdef QT3_SUPPORT
public:
QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(QObject *parent, const char *name);

View File

@ -97,10 +97,6 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
extern bool qt_applefontsmoothing_enabled;
#endif
#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
# define QT_MAX_CACHED_GLYPH_SIZE 64
#endif
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
////////////////////////////////// Private Methods //////////////////////////////////////////
@ -1441,8 +1437,7 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
// don't try to cache huge fonts or vastly transformed fonts
QFontEngine *fontEngine = textItem->fontEngine();
const qreal pixelSize = fontEngine->fontDef.pixelSize;
if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE ||
det < 0.25f || det > 4.f) {
if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) {
QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0
? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat)
: d->glyphCacheType;
@ -1500,8 +1495,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
// don't try to cache huge fonts or vastly transformed fonts
const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE ||
det < 0.25f || det > 4.f)
if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f)
drawCached = false;
QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0

View File

@ -347,13 +347,13 @@ static void find_trans_colors()
QGLFormat UNIX/GLX-specific code
*****************************************************************************/
void* qglx_getProcAddress(const char* procName)
void (*qglx_getProcAddress(const char* procName))()
{
// On systems where the GL driver is pluggable (like Mesa), we have to use
// the glXGetProcAddressARB extension to resolve other function pointers as
// the symbols wont be in the GL library, but rather in a plugin loaded by
// the GL library.
typedef void* (*qt_glXGetProcAddressARB)(const char *);
typedef void (*(*qt_glXGetProcAddressARB)(const char *))();
static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
static bool triedResolvingGlxGetProcAddress = false;
if (!triedResolvingGlxGetProcAddress) {
@ -378,7 +378,7 @@ void* qglx_getProcAddress(const char* procName)
}
}
void *procAddress = 0;
void (*procAddress)() = 0;
if (glXGetProcAddressARB)
procAddress = glXGetProcAddressARB(procName);
@ -387,7 +387,7 @@ void* qglx_getProcAddress(const char* procName)
if (!procAddress) {
void *handle = dlopen(NULL, RTLD_LAZY);
if (handle) {
procAddress = dlsym(handle, procName);
procAddress = (void (*)())dlsym(handle, procName);
dlclose(handle);
}
}

View File

@ -93,7 +93,7 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;
#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
#define glXMakeContextCurrent qt_glXMakeContextCurrent
extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp
extern void (*qglx_getProcAddress(const char* procName))(); // in qgl_x11.cpp
static bool qt_resolve_pbuffer_extensions()
{

View File

@ -218,8 +218,8 @@ static const char * x11_atomnames = {
\c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes
version.
*/
static void* qt_load_library_runtime(const char *library, int vernum,
int highestVernum, const char *symbol)
static QFunctionPointer qt_load_library_runtime(const char *library, int vernum,
int highestVernum, const char *symbol)
{
QList<int> versions;
// we try to load in the following order:
@ -234,7 +234,7 @@ static void* qt_load_library_runtime(const char *library, int vernum,
Q_FOREACH(int version, versions) {
QLatin1String libName(library);
QLibrary xfixesLib(libName, version);
void *ptr = xfixesLib.resolve(symbol);
QFunctionPointer ptr = xfixesLib.resolve(symbol);
if (ptr)
return ptr;
}

View File

@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE
returns false.
*/
class QRelatedTableModel;
struct QRelation
{
public:
@ -135,7 +137,7 @@ struct QRelation
bool isValid();
QSqlRelation rel;
QSqlTableModel *model;
QRelatedTableModel *model;
QHash<QString, QVariant> dictionary;//maps keys to display values
private:
@ -143,6 +145,15 @@ struct QRelation
bool m_dictInitialized;
};
class QRelatedTableModel : public QSqlTableModel
{
public:
QRelatedTableModel(QRelation *rel, QObject *parent = 0, QSqlDatabase db = QSqlDatabase());
bool select();
private:
bool firstSelect;
QRelation *relation;
};
/*
A QRelation must be initialized before it is considered valid.
Note: population of the model and dictionary are kept separate
@ -162,7 +173,7 @@ void QRelation::populateModel()
Q_ASSERT(m_parent != NULL);
if (!model) {
model = new QSqlTableModel(m_parent, m_parent->database());
model = new QRelatedTableModel(this, m_parent, m_parent->database());
model->setTable(rel.tableName());
model->select();
}
@ -219,6 +230,27 @@ bool QRelation::isValid()
return (rel.isValid() && m_parent != NULL);
}
QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, QSqlDatabase db) :
QSqlTableModel(parent, db), firstSelect(true), relation(rel)
{
}
bool QRelatedTableModel::select()
{
if (firstSelect) {
firstSelect = false;
return QSqlTableModel::select();
}
relation->clearDictionary();
bool res = QSqlTableModel::select();
if (res)
relation->populateDictionary();
return res;
}
class QSqlRelationalTableModelPrivate: public QSqlTableModelPrivate
{
Q_DECLARE_PUBLIC(QSqlRelationalTableModel)

View File

@ -88,7 +88,7 @@ qpa:mac: {
load(qt_module_config)
HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestlibversion.h
HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestversion.h
QMAKE_TARGET_PRODUCT = QTestLib
QMAKE_TARGET_DESCRIPTION = Qt \

View File

@ -55,7 +55,7 @@ void QRawFontPrivate::platformCleanUp()
extern int qt_defaultDpi();
void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
// Mac OS X ignores it

View File

@ -529,7 +529,8 @@ void QRawFontPrivate::platformCleanUp()
{
if (fontHandle != NULL) {
if (ptrRemoveFontMemResourceEx == NULL) {
void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
QFunctionPointer func =
QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
ptrRemoveFontMemResourceEx =
reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
}
@ -545,7 +546,7 @@ void QRawFontPrivate::platformCleanUp()
}
void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData,
int pixelSize,
qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
QByteArray fontData(_fontData);
@ -572,7 +573,8 @@ void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData,
}
if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) {
void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
QFunctionPointer func =
QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
ptrRemoveFontMemResourceEx =
reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);

View File

@ -513,7 +513,7 @@ void QKeyMapperPrivate::clearMappings()
// ### ???
// if (keyboardLayoutName.isEmpty())
// qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ?
// qWarning("Qt: unable to determine keyboard layout, please talk to qt-info@nokia.com"); ?
keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName);
keyboardInputDirection = keyboardInputLocale.textDirection();

View File

@ -148,6 +148,8 @@ public:
void clear();
QTabBar* tabBar() const;
public Q_SLOTS:
void setCurrentIndex(int index);
void setCurrentWidget(QWidget *widget);
@ -165,7 +167,6 @@ protected:
void keyPressEvent(QKeyEvent *);
void paintEvent(QPaintEvent *);
void setTabBar(QTabBar *);
QTabBar* tabBar() const;
void changeEvent(QEvent *);
bool event(QEvent *);
void initStyleOption(QStyleOptionTabWidgetFrame *option) const;

View File

@ -1,7 +1,6 @@
# Additional Qt project file for qtmain lib on Windows
TEMPLATE = lib
TARGET = qtmain
DESTDIR = $$QMAKE_LIBDIR_QT
QT =
CONFIG += staticlib warn_on
@ -17,5 +16,6 @@ win32 {
!win32:error("$$_FILE_ is intended only for Windows!")
load(qt_module_config)
DESTDIR = $$QMAKE_LIBDIR_QT
wince*:QMAKE_POST_LINK =

View File

@ -30,6 +30,7 @@ SUBDIRS=\
qfileinfo \
qfilesystemwatcher \
qflags \
qfreelist \
qfuture \
qfuturewatcher \
qgetputenv \

View File

@ -26,5 +26,3 @@ contains(QT_CONFIG, dbus){
QT += dbus
}
CONFIG+=insignificant_test

View File

@ -10,3 +10,5 @@ wince*|symbian: {
}
symbian: TARGET.CAPABILITY = NetworkServices
CONFIG += insignificant_test # QTBUG-20686; note, assumed unstable on all platforms

View File

@ -361,26 +361,25 @@ class DeliverInDefinedOrderObject : public QObject
QPointer<QThread> thread;
int count;
int startCount;
int loopLevel;
public:
DeliverInDefinedOrderObject(QObject *parent)
: QObject(parent), thread(0), count(0)
: QObject(parent), thread(0), count(0), startCount(0), loopLevel(0)
{ }
~DeliverInDefinedOrderObject()
{
if (!thread.isNull())
thread->wait();
}
signals:
void done();
public slots:
void start()
void startThread()
{
QVERIFY(!thread);
thread = new DeliverInDefinedOrderThread();
connect(thread, SIGNAL(progress(int)), this, SLOT(threadProgress(int)));
connect(thread, SIGNAL(finished()), this, SLOT(threadFinished()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(destroyed()), this, SLOT(start()));
connect(thread, SIGNAL(destroyed()), this, SLOT(threadDestroyed()));
thread->start();
QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1);
@ -398,21 +397,34 @@ public slots:
{
QVERIFY(count == 7);
count = 0;
thread->deleteLater();
QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1);
}
void threadDestroyed()
{
if (++startCount < 20)
startThread();
else
emit done();
}
public:
bool event(QEvent *event)
{
switch (event->type()) {
case QEvent::User:
{
(void) QEventLoop().exec();
break;
{
++loopLevel;
if (loopLevel == 2) {
// Ready. Starts a thread that emits (queued) signals, which should be handled in order
startThread();
}
case QEvent::User + 1:
QCoreApplication::postEvent(this, new QEvent(QEvent::MaxUser), -1);
(void) QEventLoop().exec();
break;
}
default:
break;
}
@ -430,11 +442,8 @@ void tst_QCoreApplication::deliverInDefinedOrder()
// causes sendPostedEvents() to recurse twice
QCoreApplication::postEvent(&obj, new QEvent(QEvent::User));
QCoreApplication::postEvent(&obj, new QEvent(QEvent::User));
// starts a thread that emits (queued) signals, which should be handled in order
obj.start();
// run for 15 seconds
QTimer::singleShot(15000, &app, SLOT(quit()));
QObject::connect(&obj, SIGNAL(done()), &app, SLOT(quit()));
app.exec();
}
#endif // QT_NO_QTHREAD
@ -524,7 +533,7 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
QCoreApplication::processEvents();
QCOMPARE(object.counter, i);
++i;
} while (t.elapsed() < 3000);
} while (t.elapsed() < 1000);
}
void tst_QCoreApplication::reexec()

View File

@ -1,6 +1,3 @@
load(qttest_p4)
QT += widgets
SOURCES += tst_qdialog.cpp
CONFIG+=insignificant_test

View File

@ -467,6 +467,22 @@ void tst_QDialog::throwInExec()
#if defined(Q_WS_MAC) || (defined(Q_WS_WINCE) && defined(_ARM_))
QSKIP("Throwing exceptions in exec() is not supported on this platform.", SkipAll);
#endif
#if defined(Q_OS_LINUX)
// C++ exceptions can't be passed through glib callbacks. Skip the test if
// we're using the glib event loop.
QByteArray dispatcher = QAbstractEventDispatcher::instance()->metaObject()->className();
if (dispatcher.contains("Glib")) {
QSKIP(
qPrintable(QString(
"Throwing exceptions in exec() won't work if %1 event dispatcher is used.\n"
"Try running with QT_NO_GLIB=1 in environment."
).arg(QString::fromLatin1(dispatcher))),
SkipAll
);
}
#endif
int caughtExceptions = 0;
try {
ExceptionDialog dialog;

View File

@ -55,6 +55,7 @@ private slots:
void validateThouSep();
void validateIntEquiv_data();
void validateIntEquiv();
void notifySignals();
};
Q_DECLARE_METATYPE(QValidator::State);
@ -244,6 +245,62 @@ void tst_QDoubleValidator::validate()
dv.setNotation(QDoubleValidator::StandardNotation);
QCOMPARE((int)dv.validate(value, dummy), (int)standard_state);
}
void tst_QDoubleValidator::notifySignals()
{
QDoubleValidator dv(0.1, 0.9, 10, 0);
QSignalSpy topSpy(&dv, SIGNAL(topChanged(double)));
QSignalSpy bottomSpy(&dv, SIGNAL(bottomChanged(double)));
QSignalSpy decSpy(&dv, SIGNAL(decimalsChanged(int)));
qRegisterMetaType<QDoubleValidator::Notation>("QDoubleValidator::Notation");
QSignalSpy notSpy(&dv, SIGNAL(notationChanged(QDoubleValidator::Notation)));
dv.setTop(0.8);
QCOMPARE(topSpy.count(), 1);
QVERIFY(dv.top() == 0.8);
dv.setBottom(0.2);
QCOMPARE(bottomSpy.count(), 1);
QVERIFY(dv.bottom() == 0.2);
dv.setRange(0.2, 0.7);
QCOMPARE(topSpy.count(), 2);
QCOMPARE(bottomSpy.count(), 1);
QCOMPARE(decSpy.count(), 1);
QVERIFY(dv.bottom() == 0.2);
QVERIFY(dv.top() == 0.7);
QVERIFY(dv.decimals() == 0.);
dv.setRange(0.3, 0.7);
QCOMPARE(topSpy.count(), 2);
QCOMPARE(bottomSpy.count(), 2);
QVERIFY(dv.bottom() == 0.3);
QVERIFY(dv.top() == 0.7);
QVERIFY(dv.decimals() == 0.);
dv.setRange(0.4, 0.6);
QCOMPARE(topSpy.count(), 3);
QCOMPARE(bottomSpy.count(), 3);
QVERIFY(dv.bottom() == 0.4);
QVERIFY(dv.top() == 0.6);
QVERIFY(dv.decimals() == 0.);
dv.setDecimals(10);
QCOMPARE(decSpy.count(), 2);
QVERIFY(dv.decimals() == 10.);
dv.setRange(0.4, 0.6, 100);
QCOMPARE(topSpy.count(), 3);
QCOMPARE(bottomSpy.count(), 3);
QCOMPARE(decSpy.count(), 3);
QVERIFY(dv.bottom() == 0.4);
QVERIFY(dv.top() == 0.6);
QVERIFY(dv.decimals() == 100.);
dv.setNotation(QDoubleValidator::StandardNotation);
QCOMPARE(notSpy.count(), 1);
QVERIFY(dv.notation() == QDoubleValidator::StandardNotation);
}
void tst_QDoubleValidator::validateIntEquiv_data()
{

View File

@ -41,4 +41,4 @@ symbian {
LIBS+=-lefsrv
}
CONFIG+=insignificant_test
mac*:CONFIG+=insignificant_test

View File

@ -2438,7 +2438,7 @@ void tst_QFile::rename_data()
QTest::newRow("a -> b") << QString("a") << QString("b") << false;
QTest::newRow("a -> .") << QString("a") << QString(".") << false;
QTest::newRow("renamefile -> renamefile") << QString("renamefile") << QString("renamefile") << false;
QTest::newRow("renamefile -> Makefile") << QString("renamefile") << QString("Makefile") << false;
QTest::newRow("renamefile -> noreadfile") << QString("renamefile") << QString("noreadfile") << false;
#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
QTest::newRow("renamefile -> /etc/renamefile") << QString("renamefile") << QString("/etc/renamefile") << false;
#endif

View File

@ -15,5 +15,3 @@ symbian: {
DEPLOYMENT += dummyDeploy
LIBS += -lefsrv
}
CONFIG+=insignificant_test

View File

@ -909,12 +909,16 @@ void tst_QFileSystemModel::sort()
expectedOrder << tempFile2.fileName() << tempFile.fileName() << dirPath + QChar('/') + "." << dirPath + QChar('/') + "..";
//File dialog Mode means sub trees are not sorted, only the current root
if (fileDialogMode) {
// FIXME: we were only able to disableRecursiveSort in developer builds, so we can only
// stably perform this test for developer builds
#ifdef QT_BUILD_INTERNAL
QList<QString> actualRows;
for(int i = 0; i < myModel->rowCount(parent); ++i)
{
actualRows << dirPath + QChar('/') + myModel->index(i, 1, parent).data(QFileSystemModel::FileNameRole).toString();
}
QVERIFY(actualRows != expectedOrder);
#endif
} else {
for(int i = 0; i < myModel->rowCount(parent); ++i)
{

View File

@ -0,0 +1,6 @@
load(qttest_p4)
SOURCES += tst_qfreelist.cpp
QT += core-private
QT -= gui
!private_tests:SOURCES += $$QT_SOURCE_TREE/src/corelib/tools/qfreelist.cpp

View File

@ -0,0 +1,179 @@
/****************************************************************************
**
** 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 test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
#include <QtCore/QList>
#include <QtCore/QThread>
#include <private/qfreelist_p.h>
#include <QtTest/QtTest>
//TESTED_CLASS=QFreeList
//TESTED_FILES=corelib/tools/qfreelist_p.h
class tst_QFreeList : public QObject
{
Q_OBJECT
private slots:
void basicTest();
void customized();
void threadedTest();
};
void tst_QFreeList::basicTest()
{
{
QFreeList<void> voidFreeList;
int zero = voidFreeList.next();
int one = voidFreeList.next();
int two = voidFreeList.next();
QCOMPARE(zero, 0);
QCOMPARE(one, 1);
QCOMPARE(two, 2);
voidFreeList[zero];
voidFreeList[one];
voidFreeList[two];
voidFreeList.at(zero);
voidFreeList.at(one);
voidFreeList.at(two);
voidFreeList.release(one);
int next = voidFreeList.next();
QCOMPARE(next, 1);
voidFreeList[next];
voidFreeList.at(next);
}
{
QFreeList<int> intFreeList;
int zero = intFreeList.next();
int one = intFreeList.next();
int two = intFreeList.next();
QCOMPARE(zero, 0);
QCOMPARE(one, 1);
QCOMPARE(two, 2);
intFreeList[zero] = zero;
intFreeList[one] = one;
intFreeList[two] = two;
QCOMPARE(intFreeList.at(zero), zero);
QCOMPARE(intFreeList.at(one), one);
QCOMPARE(intFreeList.at(two), two);
intFreeList.release(one);
int next = intFreeList.next();
QCOMPARE(next, 1);
QCOMPARE(intFreeList.at(next), one);
intFreeList[next] = -one;
QCOMPARE(intFreeList.at(next), -one);
}
}
struct CustomFreeListConstants : public QFreeListDefaultConstants
{
enum {
InitialNextValue = 50,
BlockCount = 10
};
static const int Sizes[10];
};
const int CustomFreeListConstants::Sizes[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16777216 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 };
void tst_QFreeList::customized()
{
QFreeList<void, CustomFreeListConstants> customFreeList;
int next = customFreeList.next();
QCOMPARE(next, int(CustomFreeListConstants::InitialNextValue));
customFreeList[next];
customFreeList.at(next);
customFreeList.release(next);
}
enum { TimeLimit = 3000 };
class FreeListThread : public QThread
{
static QFreeList<void> freelist;
public:
inline FreeListThread() : QThread() { }
inline void run()
{
QElapsedTimer t;
t.start();
QList<int> needToRelease;
do {
int i = freelist.next();
int j = freelist.next();
int k = freelist.next();
int l = freelist.next();
freelist.release(k);
int n = freelist.next();
int m = freelist.next();
freelist.release(l);
freelist.release(m);
freelist.release(n);
freelist.release(j);
// freelist.release(i);
needToRelease << i;
} while (t.elapsed() < TimeLimit);
foreach (int x, needToRelease)
freelist.release(x);
}
};
QFreeList<void> FreeListThread::freelist;
void tst_QFreeList::threadedTest()
{
const int ThreadCount = QThread::idealThreadCount();
FreeListThread *threads = new FreeListThread[ThreadCount];
for (int i = 0; i < ThreadCount; ++i)
threads[i].start();
for (int i = 0; i < ThreadCount; ++i)
threads[i].wait();
delete [] threads;
}
QTEST_MAIN(tst_QFreeList)
#include "tst_qfreelist.moc"

View File

@ -18,5 +18,3 @@ wince*: {
} else {
DEFINES += SRCDIR=\\\"$$PWD/\\\"
}
CONFIG+=insignificant_test

View File

@ -378,6 +378,8 @@ void tst_QFtp::connectToUnresponsiveHost()
a lot of other stuff in QFtp, so we just expect this test to fail on Windows.
*/
QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort);
#else
QEXPECT_FAIL("", "QTBUG-20687", Abort);
#endif
QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)");

View File

@ -130,10 +130,12 @@ void tst_QGlobal::qInternalCallbacks()
QInternal::unregisterCallback(QInternal::DisconnectCallback, disconnect_callback);
connect_info.reset();
QTest::ignoreMessage(QtWarningMsg, "Object::connect: No such signal QObject::mysignal(x)");
ok = QObject::connect(&a, signal.toLatin1(), &b, slot.toLatin1(), Qt::AutoConnection);
QVERIFY(!ok);
QCOMPARE(connect_info.sender, (QObject *) 0);
QTest::ignoreMessage(QtWarningMsg, "Object::disconnect: No such signal QObject::mysignal(x)");
ok = QObject::disconnect(&a, signal.toLatin1(), &b, slot.toLatin1());
QVERIFY(!ok);
QCOMPARE(connect_info.sender, (QObject *) 0);

View File

@ -2,5 +2,3 @@ load(qttest_p4)
QT += widgets
SOURCES += tst_qgraphicstransform.cpp
CONFIG += parallel_test
CONFIG+=insignificant_test

Some files were not shown because too many files have changed in this diff Show More