sorry że tyle wklejam, ale niech ktoś mądry powie, jak pozbyć się break'ów z tego kodu tak, aby nie robić zbędnych porównań (nie sprawdzać w kilku miejscach wartości zmiennej n) :]
zwycięzca dostanie uśmiech sołtysa odciśnięty w betonie.
(...)
Kopiuj
function create():Boolean;
begin
if h <> 0 then // semafor na tym połączeniu już utworzony
begin
i := 0;
send(sock,i,4,0);
lasterror := TCP_SEMAPHORE_ALREADY_OPENED;
Result := false;
Exit();
end;
delete(n,1,7);
p1 := strtoint(copy(n,1,pos(' ',n)-1));
delete(n,1,pos(' ',n));
p2 := strtoint(copy(n,1,pos(' ',n)-1));
delete(n,1,pos(' ',n));
n := n + #0;
i := CreateSemaphore(nil,p1,p2,pchar(@n));
h := i;
lasterror := GetLastError;
send(sock,i,4,0);
Result := true;
end;
function open():Boolean;
begin
if h <> 0 then // semafor na tym połączeniu już utworzony
begin
i := 0;
send(sock,i,4,0);
lasterror := TCP_SEMAPHORE_ALREADY_OPENED;
Result := false;
Exit();
end;
delete(n,1,5);
p1 := strtoint(copy(n,1,pos(' ',n)-1));
delete(n,1,pos(' ',n));
p2 := byte(copy(n,1,pos(' ',n)-1) = 'TRUE');
delete(n,1,pos(' ',n));
n := n + #0;
i := OpenSemaphore(p1,boolean(p2),pchar(@n));
h := i;
lasterror := GetLastError;
send(sock,i,4,0);
Result := true;
end;
function wait():Boolean;
begin
delete(n,1,5);
p1 := strtoint(n); {timeout}
i := WaitForSingleObject(h,p1);
lasterror := GetLastError;
send(sock,i,4,0);
Result := true;
end;
function release():Boolean;
begin
delete(n,1,8);
p1 := strtoint(n); {count}
if (not ReleaseSemaphore(h,p1,@i)) then i := -1;
lasterror := GetLastError;
send(sock,i,4,0);
Result := true;
end;
function close():Boolean;
begin
if h = 0 then // semafor na tym połączeniu nie był utworzony
begin
i := -1;
send(sock,i,4,0);
lasterror := TCP_SEMAPHORE_NOT_OPENED;
Result := false;
Exit();
end;
if (not CloseHandle(h)) then i := -1 else begin i := 0; h := 0; end;
lasterror := GetLastError;
send(sock,i,4,0);
Result := true;
end;
begin
h := 0;
lasterror := 0;
EnterCriticalSection(threadlock);
if threadcount >= MAX_CONNECTIONS then
begin
printresult(format('CONNECTION REFUSED for socket %d (thread %d) [%d from %d]',[sock,self.Handle,threadcount+1,MAX_CONNECTIONS]));
Kopiuj
closesocket(sock);
exit;
end else threadcount := InterlockedIncrement(threadcount);
LeaveCriticalSection(threadlock);
try
printresult(format('CONNECTION OPENED for socket %d (thread %d) [%d from %d]',[sock,self.Handle,threadcount,MAX_CONNECTIONS]));
Kopiuj
while not Application.Terminated and (i <> WSAECONNRESET) and wynik do
begin
n := '';
i := recv(sock,n[1],255,0);
setlength(n,i);
n2 := n;
if (i <= 0) or (i = WSAECONNRESET) then
wynik := false;
else if (n = 'QUIT') or (n = 'BYE') or (n = 'EXIT') then
wynik := false; // semafor i tak zostanie zwolniony;
else if n = 'GETLASTERROR' then
begin
i := lasterror;
send(sock,i,4,0);
wynik := true;
end else if copy(n,1,7) = 'CREATE ' then // CREATE value max name
wynik := create();
else if copy(n,1,5) = 'OPEN ' then // OPEN options inherit name
wynik := open();
else if copy(n,1,5) = 'WAIT ' then // WAIT timeout
wynik := wait();
else if copy(n,1,8) = 'RELEASE ' then // RELEASE count => -1=ERROR
wynik := release();
else if n = 'CLOSE' then // CLOSE => -1=ERROR
wynik := close();
else
begin
i := -1;
lasterror := TCP_SEMAPHORE_WRONG_COMMAND;
send(sock,i,4,0);
printresult(format('INCORRECT COMMAND: %s, CLOSING CONNECTION for socket %d (thread %d)',[n2,i,i,sock,self.Handle]));
Kopiuj
wynik := false;
end;
if wynik then
printresult(format('GOT: %s, SENT: %d (%x) for socket %d (thread %d)',[n2,i,i,sock,self.Handle]));
printresult(format('CONNECTION CLOSED for socket %d (thread %d)',[sock,self.Handle]));
Kopiuj
finally
threadcount := InterlockedDecrement(threadcount);
if not Application.Terminated then
begin
if h <> 0 then CloseHandle(h);
closesocket(sock);
Free;
end;
end;
end;
Do funkcji trzeba oczywiscie poprzekazywac odpowiednie prametry. Sa tylko o 2 wiecej porownania, sprawdzajace wartosc zmiennej boolowskiej wynik.
Wciaz mi sie kod nie podoba, bo funkcja zajmuje mi 1,5 ekranu, ale nie mam ochoty wiecej tego przerabiac. Natomiast sprobowalbym zamiast kilka razy robic copy sprobowac wyciac raz tylko 5 pierwszych znakow i dla tych, co maja byc dluzsze niz 5, porownywac tylko z 5 pierwszymi znakami (albo lepiej 4 i zbic do 1 liczby). Oczywiscie o ile nie ma mozlisoci trafienia na inne tego typu "poczatki". W kazdym badz razie jezeli liczba tych mozliwych wartosci jest niewielka, to jakies haszowanie byloby wskazane.
P.S. nie, zebym byl przeciwnikiem calkowitego uzycia break, continue czy goto. Po prostu chcialem pokazac, ze to akurat da sie, zapisac bez break. Ale switch-a w C bez break, to raczej nie jestem w stanie napisac. Co więcej wcale nie chce. Czesto breaki stosuje w ifach. Goto raczej nie koniecznie...