Browse Source

Merge pull request #97 from ceccopierangiolieugenio/TTkStringOptimization

Strings optimization
pull/98/merge
Ceccopierangiolieugenio 3 years ago committed by GitHub
parent
commit
7e6964dbed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .github/workflows/testing.yml
  2. 3
      Makefile
  3. 33
      TermTk/TTkCore/string.py
  4. 24
      TermTk/TTkTestWidgets/testwidget.py
  5. 11
      tests/pytest/test_001_demo.py
  6. 112
      tests/timeit/09.widechar.check.py

3
.github/workflows/testing.yml

@ -47,7 +47,8 @@ jobs:
run: |
# Download the input test
mkdir -p tmp
wget -O tmp/test.input.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.001.bin
wget -O tmp/test.input.001.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.001.bin
wget -O tmp/test.input.002.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.002.bin
pytest tests/pytest/test_003_string.py
pytest tests/pytest/test_002_textedit.py
pytest tests/pytest/test_001_demo.py

3
Makefile

@ -91,7 +91,8 @@ test: .venv
# Play the test stream
# tests/pytest/test_001_demo.py -p test.input.bin
mkdir -p tmp
wget -O tmp/test.input.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.001.bin
wget -O tmp/test.input.001.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.001.bin
wget -O tmp/test.input.002.bin https://github.com/ceccopierangiolieugenio/binaryRepo/raw/master/pyTermTk/tests/test.input.002.bin
tools/check.import.sh
. .venv/bin/activate ; \
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude .venv,build,tmp ; \

33
TermTk/TTkCore/string.py

@ -103,16 +103,20 @@ class TTkString():
if isinstance(other, TTkString):
ret._text = self._text + other._text
ret._colors = self._colors + other._colors
ret._hasTab = '\t' in ret._text
ret._fastCheckWidth(self._hasSpecialWidth, other._hasSpecialWidth)
elif isinstance(other, str):
atxt, acol = TTkString._parseAnsi(other, self._baseColor)
ret._text = self._text + atxt
ret._colors = self._colors + acol
ret._hasTab = '\t' in ret._text
ret._checkWidth()
elif isinstance(other, _TTkColor):
ret._text = self._text
ret._colors = self._colors
ret._hasSpecialWidth = self._hasSpecialWidth
ret._hasTab = self._hasTab
ret._baseColor = other
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
def __radd__(self, other):
@ -121,11 +125,13 @@ class TTkString():
if isinstance(other, TTkString):
ret._text = other._text + self._text
ret._colors = other._colors + self._colors
ret._hasTab = '\t' in ret._text
ret._fastCheckWidth(self._hasSpecialWidth, other._hasSpecialWidth)
elif isinstance(other, str):
ret._text = other + self._text
ret._colors = [self._baseColor]*len(other) + self._colors
ret._hasTab = '\t' in ret._text
ret._checkWidth()
ret._hasTab = '\t' in ret._text
ret._checkWidth()
return ret
def __setitem__(self, index, value):
@ -182,7 +188,7 @@ class TTkString():
spaces = tabSpaces - (lentxt+tabSpaces)%tabSpaces
ret._text += " "*spaces + s
ret._colors += [c]*spaces + self._colors[pos+1:pos+1+len(s)]
ret._checkWidth()
ret._fastCheckWidth(self._hasSpecialWidth)
pos+=len(s)+1
return ret
@ -328,7 +334,7 @@ class TTkString():
ret._colors = self._colors[:width]
ret._hasTab = '\t' in ret._text
ret._checkWidth()
ret._fastCheckWidth(self._hasSpecialWidth)
return ret
@ -467,7 +473,7 @@ class TTkString():
ret._text = self._text[fr:to]
ret._colors = self._colors[fr:to]
ret._hasTab = '\t' in ret._text
ret._checkWidth()
ret._fastCheckWidth(self._hasSpecialWidth)
return ret
def split(self, separator ):
@ -578,10 +584,17 @@ class TTkString():
return pos-i-1
return 0
def _fastCheckWidth(self,a,b=None):
self._hasSpecialWidth = None if (
a is None and b is None ) else self._termWidthW()
def _checkWidth(self):
self._hasSpecialWidth = self._termWidthW() if (
any(unicodedata.east_asian_width(ch) == 'W' for ch in self._text) or
any(unicodedata.category(ch) in ('Me','Mn') for ch in self._text) ) else None
# from: tests/timeit/09.widechar.check.py
# the first not halfsize char is 0x300
# this check is ~3 times faster than the 2 combined unicode checks
# and will quickly filter out the (more common) simple ascii text
tw = self._termWidthW() if any(ord(ch)>=0x300 for ch in self._text) else None
self._hasSpecialWidth = tw if tw != len(self._text) else None
def _termWidthW(self):
''' String displayed length

24
TermTk/TTkTestWidgets/testwidget.py

@ -31,16 +31,24 @@ from TermTk.TTkWidgets.label import *
from TermTk.TTkWidgets.frame import *
class _TestContent(TTkWidget):
t01 = TTkString(color=TTkColor.fg("#ff0000") ,text=" L😎rem ipsum dolor sit amet, ⌚ ❤ 💙 🙋'")
t02 = TTkString(color=TTkColor.fg("#ff8800") ,text="consectetur adipiscing elit,")
t03 = TTkString(color=TTkColor.fg("#ffff00") ,text="sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
t04 = TTkString(color=TTkColor.fg("#00ff00") ,text="Ut enim ad minim veniam,")
t05 = TTkString(color=TTkColor.fg("#00ffff") ,text="quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")
t06 = TTkString(color=TTkColor.fg("#0088ff") ,text="Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.")
t07 = TTkString(color=TTkColor.fg("#0000ff") ,text="Excepteur sint occaecat cupidatat non proident,")
t08 = TTkString(color=TTkColor.fg("#ff00ff") ,text="sunt in culpa qui officia deserunt mollit anim id est laborum.")
def paintEvent(self):
# TTkLog.debug(f"Test Paint - {self._name}")
y=0; self._canvas.drawText(pos=(-5,y),text=TTkString(color=TTkColor.fg("#ff0000") ,text=" L😎rem ipsum dolor sit amet, ⌚ ❤ 💙 🙋'"))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#ff8800") ,text="consectetur adipiscing elit,"))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#ffff00") ,text="sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#00ff00") ,text="Ut enim ad minim veniam,"))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#00ffff") ,text="quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#0088ff") ,text="Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#0000ff") ,text="Excepteur sint occaecat cupidatat non proident,"))
y+=1; self._canvas.drawText(pos=(0,y), text=TTkString(color=TTkColor.fg("#ff00ff") ,text="sunt in culpa qui officia deserunt mollit anim id est laborum."))
y=0; self._canvas.drawText(pos=(-5,y), text=self.t01)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t02)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t03)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t04)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t05)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t06)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t07)
y+=1; self._canvas.drawText(pos=( 0,y), text=self.t08)
y+=1; self._canvas.drawGrid(
pos=(0,y),size=(self._width,self._height-y),
hlines=(2,5,7), vlines=(4,7,15,30),

11
tests/pytest/test_001_demo.py

@ -166,7 +166,16 @@ def test_recording1():
# demo.ttk.TTkLog.use_default_file_logging()
demo.ttk.TTkLog.installMessageHandler(message_handler)
root = TTkRecord(title="pyTermTk Demo Record", record=False)
root.loadQueue(open('tmp/test.input.bin', 'rb'))
root.loadQueue(open('tmp/test.input.001.bin', 'rb'))
winTabbed1 = demo.ttk.TTkWindow(parent=root,pos=(0,0), size=(80,24), title="pyTermTk Showcase", border=True, layout=demo.ttk.TTkGridLayout())
demo.demoShowcase(winTabbed1, True)
root.mainloop()
def test_recording2():
# demo.ttk.TTkLog.use_default_file_logging()
demo.ttk.TTkLog.installMessageHandler(message_handler)
root = TTkRecord(title="pyTermTk Demo Record", record=False)
root.loadQueue(open('tmp/test.input.002.bin', 'rb'))
winTabbed1 = demo.ttk.TTkWindow(parent=root,pos=(0,0), size=(80,24), title="pyTermTk Showcase", border=True, layout=demo.ttk.TTkGridLayout())
demo.demoShowcase(winTabbed1, True)
root.mainloop()

112
tests/timeit/09.widechar.check.py

@ -0,0 +1,112 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import sys, os
import timeit
import random
import unicodedata
sys.path.append(os.path.join(sys.path[0],'../..'))
sys.path.append(os.path.join(sys.path[0],'.'))
import TermTk as ttk
# first Zero size char 0x00300
# first Full size char 0x01100
print(f"Create CharSetStringTest...")
cstr = ""
cstrw = ""
for _ in range(0x4000):
cstr += chr(random.randint(0x100,0x2FF))
cstrw += chr(random.randint(0x100,0x20000))
print(f"Create CharSetStringTest DONE!!!")
print(f"len cstr 0x{len(cstr):04x}")
print(f"len cstrw 0x{len(cstrw):04x}")
# print([f"'{ch}':{unicodedata.east_asian_width(ch)}:{unicodedata.category(ch)}" for ch in cstr])
# print([f"'{ch}':{unicodedata.east_asian_width(ch)}:{unicodedata.category(ch)}" for ch in cstrw])
def _tw(text):
return ( len(text) +
sum(unicodedata.east_asian_width(ch) == 'W' for ch in text) -
sum(unicodedata.category(ch) in ('Me','Mn') for ch in text) )
def test1(text):
return ( len(text) +
sum(unicodedata.east_asian_width(ch) == 'W' for ch in text) -
sum(unicodedata.category(ch) in ('Me','Mn') for ch in text) )
def test2(text):
tw = _tw(text) if any(ord(ch)>=0x300 for ch in text) else None
return tw if tw != len(text) else None
def test3(text):
return ( any(unicodedata.east_asian_width(ch) == 'W' for ch in text) or
any(unicodedata.category(ch) in ('Me','Mn') for ch in text) )
def test4(text):
return (any(ord(ch)>=0x300 for ch in text) and
( any(unicodedata.east_asian_width(ch) == 'W' for ch in text) or
any(unicodedata.category(ch) in ('Me','Mn') for ch in text) ) )
def test5(text):
return any(ord(ch)>=0x300 for ch in text)
def test6(text):
return any(ord(ch)>=0x300 for ch in text)
loop = 200
a=cstr
result = timeit.timeit('test1(a)', globals=globals(), number=loop)
print(f"1a {result / loop:.10f} - {result / loop} {test1(a)}")
result = timeit.timeit('test2(a)', globals=globals(), number=loop)
print(f"2a {result / loop:.10f} - {result / loop} {test2(a)}")
result = timeit.timeit('test3(a)', globals=globals(), number=loop)
print(f"3a {result / loop:.10f} - {result / loop} {test3(a)}")
result = timeit.timeit('test4(a)', globals=globals(), number=loop)
print(f"4a {result / loop:.10f} - {result / loop} {test4(a)}")
result = timeit.timeit('test5(a)', globals=globals(), number=loop)
print(f"5a {result / loop:.10f} - {result / loop} {test5(a)}")
result = timeit.timeit('test6(a)', globals=globals(), number=loop)
print(f"6a {result / loop:.10f} - {result / loop} {test6(a)}")
a=cstrw
result = timeit.timeit('test1(a)', globals=globals(), number=loop)
print(f"1b {result / loop:.10f} - {result / loop} {test1(a)}")
result = timeit.timeit('test2(a)', globals=globals(), number=loop)
print(f"2b {result / loop:.10f} - {result / loop} {test2(a)}")
result = timeit.timeit('test3(a)', globals=globals(), number=loop)
print(f"3b {result / loop:.10f} - {result / loop} {test3(a)}")
result = timeit.timeit('test4(a)', globals=globals(), number=loop)
print(f"4b {result / loop:.10f} - {result / loop} {test4(a)}")
result = timeit.timeit('test5(a)', globals=globals(), number=loop)
print(f"5b {result / loop:.10f} - {result / loop} {test5(a)}")
result = timeit.timeit('test6(a)', globals=globals(), number=loop)
print(f"6b {result / loop:.10f} - {result / loop} {test6(a)}")
Loading…
Cancel
Save