| Ticket UUID: | 458446 | |||
| Title: | BWidget: faster ListBox inserts | |||
| Type: | Patch | Version: | None | |
| Submitter: | bach | Created on: | 2001-09-04 16:52:03 | |
| Subsystem: | bwidget | Assigned To: | hobbs | |
| Priority: | 5 Medium | Severity: | ||
| Status: | Closed | Last Modified: | 2001-12-29 08:33:24 | |
| Resolution: | Fixed | Closed By: | hobbs | |
| Closed on: | 2001-12-29 01:33:24 | |||
| Description: |
Motivation:
The BWidget ListBox insert command isn't a speed demon.
This is not
too noticable for small lists, but it gets rather slow
for big ones
E.g. inserting 500 entries with just -text and -image
attributes set
takes approx. 1 second on a Pentium III 550MHz.
Problem analysis:
The bulk of the time in ListBox::insert gets eaten by a
call to
Widget::init. In Widget::init, most of the time is used
by
initializing and parsing from standard options
database. The example
from above uses ~1250msec for building up the std.
options and
~250msec to apply specific options for the item.
Proposed patch:
Two functions to speed up inserts of many items that
are all almost
equal.
First, Widget::copyinit. This works almost like the
normal init, but
saves time by copying standard option initialization
from a given
template. It then applies specific item options (just
like init).
Second, ListBox::multipleinsert. This also works like
its pendant
ListBox::insert, but knows about the aforementioned
Widget::copyinit
function. I shortly thought of changing the original
'insert', but the
effects of a change there would not be backward
compatible.
Sideeffects:
None to existing code. A widget function more to
document for the user
(ListBox::multipleinsert).
Results:
The speedup of using multipleinsert is a factor of 2
when used almost
exactly like a multiple call to insert.
That is:
set l
foreach n {name1 name2 name3 ... namen} {
lappend l $n "-text $n -image something.gif"
}
$list multipleinsert end $l
is 2 times faster than its pendant
foreach n {name1 name2 name3 ... namen} {
$list insert end $n -text $n -image
something.gif
}
Assuming that, e.g. all images used are the same (as in
the example
above, the speedup is factor 3 by using:
set l
foreach n {name1 name2 name3 ... namen} {
if {[llength $l] == 0} {
lappend l $n "-text $n -image
something.gif"
} else {
lappend l $n "-text $n"
}
$list multipleinsert end $l
Code:
In listbox.tcl:
# Bastien Chevreux (bach@mwgdna.com)
# The multipleinsert command performs inserts several
items at once into
# the list. It is faster than calling insert multiple
times as it uses the
# Widget::copyinit command for initializing all items
after the 1st. The
# speedup factor is between 2 and 3 for typical usage,
but could be higher
# for inserts with many options.
#
# Syntax: path and index are as in the insert command
# args is a list of even numbered elements
where the 1st of each pair
# corresponds to the item of 'insert' and the
second to args of 'insert'.
#
------------------------------------------------------------------------------
# Command ListBox::multipleinsert
#
------------------------------------------------------------------------------
proc ListBox::multipleinsert { path index args } {
variable $path
upvar 0 $path data
# If we got only one list as arg, take the first
element as args
# This enables callers to use
# $list multipleinsert index $thelist
# instead of
# eval $list multipleinsert index $thelist
if {[llength $args] == 1} {
set args [lindex $args 0]
}
set count 0
foreach {item iargs} $args {
if { [lsearch $data(items) $item] != -1 } {
return -code error "item \"$item\" already exists"
}
if {$count==0} {
Widget::init ListBox::Item $path.$item $iargs
set firstpath $path.$item
} else {
Widget::copyinit ListBox::Item $firstpath
$path.$item $iargs
}
if { ![string compare $index "end"] } {
eval lappend data(items) $item
} else {
set data(items) [linsert $data(items) $index
$item]
}
set data(upd,create,$item) $item
incr count
}
_redraw_idle $path 2
return $item
}
In widget.tcl:
# Bastien Chevreux (bach@mwgdna.com)
#
# copyinit performs basically the same job as init, but
it uses a
# existing template to initialize its values. So,
first a perferct copy
# from the template is made just to be altered by any
existing options
# afterwards.
# But this still saves time as the first initialization
parsing block is
# skipped.
# As additional bonus, items that differ in just a few
options can be
# initialized faster by leaving out the options that
are equal.
# This function is currently used only by
ListBox::multipleinsert, but other
# calls should follow :)
#
------------------------------------------------------------------------------
# Command Widget::copyinit
#
------------------------------------------------------------------------------
proc Widget::copyinit { class templatepath path options
} {
upvar 0 ${class}::opt classopt
upvar 0 ${class}::$path:opt pathopt
upvar 0 ${class}::$path:mod pathmod
upvar 0 ${class}::$path:init pathinit
upvar 0 ${class}::$templatepath:opt
templatepathopt
upvar 0 ${class}::$templatepath:mod
templatepathmod
upvar 0 ${class}::$templatepath:init
templatepathinit
if { [info exists pathopt] } {
unset pathopt
}
if { [info exists pathmod] } {
unset pathmod
}
# We use the template widget for option db copying,
but it has to exist!
array set pathmod [array get templatepathmod]
array set pathopt [array get templatepathopt]
array set pathinit [array get templatepathinit]
set Widget::_class($path) $class
foreach {option value} $options {
if { ![info exists classopt($option)] } {
unset pathopt
unset pathmod
return -code error "unknown option
\"$option\""
}
set optdesc $classopt($option)
set type [lindex $optdesc 0]
if { ![string compare $type "Synonym"] } {
set option [lindex $optdesc 1]
set optdesc $classopt($option)
set type [lindex $optdesc 0]
}
set pathopt($option)
[$Widget::_optiontype($type) $option $value [lindex
$optdesc 3]]
set pathinit($option) $pathopt($option)
}
}
| |||
| User Comments: |
hobbs added on 2001-12-29 08:33:24:
Logged In: YES user_id=72656 added to 1.4.0.cvs patthoyts added on 2001-10-26 15:07:12: Logged In: YES user_id=202636 Reset category from tkchat to bwidget as this is a bwidget patch. bach added on 2001-09-04 23:56:26: File Added - 10369: lb_patch.txt Logged In: YES user_id=98533 *sigh* I should've learned by now to attach files and not to paste. Properly formated code is attached separately. | |||
Attachments:
- lb_patch.txt [download] added by bach on 2001-09-04 23:56:26. [details]
