473,659 Members | 2,666 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Please critique this function

The function below does exactly what I want it to (there is a main to
test it as well.) However, I'm curious about ideas of making it better.
Anyone interested in critiquing it?

void formatText( const string& in, int charsPerLine, int lines,
vector< string >& out )
{
out.resize( 1 );
out[0] = "";
int prev = 0;
int pos = charsPerLine;
int lineCount = 0;
while ( pos < in.size() ) {
pos = in.find_last_of ( " -", pos );
if ( pos < prev ) {
pos = prev + charsPerLine - 1;
out.back() += in.substr( prev, pos - prev );
out.back() += '-';
prev = pos;
}
else if ( in[pos] == '-' ) {
++pos;
out.back() += in.substr( prev, pos - prev );
prev = pos;
}
else {
out.back() += in.substr( prev, pos - prev );
prev = pos + 1;
}
out.back() += (char)0x0A;
pos += charsPerLine;
++lineCount;
if ( lines <= lineCount ) {
out.back().eras e( out.back().size () - 1 );
out.push_back( "" );
lineCount = 0;
}
}
out.back() += in.substr( prev );
}

int main()
{
string in = "hello";
vector< string out;
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "hello" );

in = "Put up with it and you will get more of it.";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Put up with it and you\nwill get more of it." );

in = "The mind of a bigot is like the pupil of the eye. The more
light you shine on it, the more it will contract.";
formatText( in, 24, 4, out );
assert( out.size() == 2 );
assert( out[0] == "The mind of a bigot is\nlike the pupil of
the\neye. The more light you\nshine on it, the more" );
assert( out[1] == "it will contract." );

in = "Floccinaucinih ilipili-fication";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Floccinaucinih ilipili-\nfication" );

in = "Floccinaucinih ilipilification ";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Floccinaucinih ilipilifi-\ncation" );

}
Oct 21 '07 #1
11 1773
"Alf P. Steinbach" <al***@start.no wrote:
However, I'm curious about ideas of making it better.
Anyone interested in critiquing it?

void formatText( const string& in, int charsPerLine, int lines,
vector< string >& out )
{
out.resize( 1 );
out[0] = "";
int prev = 0;
int pos = charsPerLine;
int lineCount = 0;
while ( pos < in.size() ) {
pos = in.find_last_of ( " -", pos );
if ( pos < prev ) {
pos = prev + charsPerLine - 1;
out.back() += in.substr( prev, pos - prev );
out.back() += '-';
prev = pos;
}
else if ( in[pos] == '-' ) {
++pos;
out.back() += in.substr( prev, pos - prev );
prev = pos;
}
else {
out.back() += in.substr( prev, pos - prev );
prev = pos + 1;
}
out.back() += (char)0x0A;
pos += charsPerLine;
++lineCount;
if ( lines <= lineCount ) {
out.back().eras e( out.back().size () - 1 );
out.push_back( "" );
lineCount = 0;
}
}
out.back() += in.substr( prev );
}

I rewrote it as follows, but I'm afraid that removed the desired UB:
I modified your re-write so it passes all the tests:

void formatText(
string const& in,
int charsPerLine,
int lines,
vector< string >& out )
{
vector<string result( 1 );

size_t prev = 0;
size_t pos = charsPerLine;
int lineCount = 0;
while ( pos < in.size() )
{
pos = in.find_last_of ( " -", pos );
if ( pos == string::npos || pos < prev )
{
pos = prev + charsPerLine - 1;
result.back() += in.substr( prev, pos - prev );
result.back() += '-';
prev = pos;
}
else if ( in.at( pos ) == '-' )
{
++pos;
result.back() += in.substr( prev, pos - prev );
prev = pos;
}
else
{
result.back() += in.substr( prev, pos - prev );
prev = pos + 1;
}
result.back() += '\n';
pos += charsPerLine;
++lineCount;
if ( lines <= lineCount )
{
result.back().e rase( result.back().s ize() - 1 );
result.push_bac k( "" );
lineCount = 0;
}
}
result.back() += in.substr( prev );
out.swap( result );
}

I see two basic differences in your code from mine...

1) You define 'pos' and 'prev' as unsigned values which exposed the UB.

2) You do all the work in the vector 'result' rather than the 'out'
parameter. I assume that is to insure that 'out' is unchanged if the
function throws?

The logic, however seems identical to mine. Can you think of any
improvements to the logic?
Oct 22 '07 #2
On Oct 22, 12:11 am, "Daniel T." <danie...@earth link.netwrote:
The function below does exactly what I want it to (there is a main to
test it as well.) However, I'm curious about ideas of making it better.
Anyone interested in critiquing it?
Well, just from the code, I have great difficulty even
understanding it. I'm not even sure what it is supposed to do.

If you're trying to break up text into lines, I don't really
understand the output; what is each entry in the vector (since
the entries themselves have line breaks)? Without a
specification of what the function is supposed to do, you can't
begin to write it, write a test for it, or ask anyone to review
it.

Otherwise: in general, if the problem is breaking up text into
lines of a maximum width, with line breaks only at word
boundaries (or other specified places), then the usual solution
would be to break the problem up into parts: a class which
breaks the input up into words, and a class which puts the words
into the destintation, adding line breaks as needed.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Oct 22 '07 #3
"Alf P. Steinbach" <al***@start.no wrote:
* Daniel T. -Alf P. Steinbach:
The logic, however seems identical to mine. Can you think of any
improvements to the logic?

formatText( "123456 123456", 6, 4, result );
Thanks. Not only did it show an anomaly in the code, but it exposed an
error in one of the other tests! Still no ideas on reducing the
complexity of the code though?

void formatText(
string const& in,
int charsPerLine,
int lines,
vector< string >& out )
{
vector<string result( 1 );

size_t prev = 0;
size_t pos = charsPerLine;
int lineCount = 0;
while ( pos < in.size() )
{
pos = in.find_last_of ( " -", pos );
if ( pos == string::npos || pos < prev )
{
pos = prev + charsPerLine - 1;
result.back() += in.substr( prev, pos - prev );
result.back() += '-';
prev = pos;
}
else if ( in.at( pos ) == '-' )
{
++pos;
result.back() += in.substr( prev, pos - prev );
prev = pos;
}
else
{
result.back() += in.substr( prev, pos - prev );
prev = pos + 1;
}
result.back() += '\n';
pos = prev + charsPerLine;
++lineCount;
if ( lines <= lineCount )
{
result.back().e rase( result.back().s ize() - 1 );
result.push_bac k( "" );
lineCount = 0;
}
}
result.back() += in.substr( prev );
out.swap( result );
}

int main()
{
string in = "hello";
vector< string out;
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "hello" );

in = "Put up with it and you will get more of it.";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Put up with it and you\nwill get more of it." );

in = "The mind of a bigot is like the pupil of the eye. The more
light you shine on it, the more it will contract.";
formatText( in, 24, 4, out );
assert( out.size() == 2 );
assert( out[0] == "The mind of a bigot is\nlike the pupil of
the\neye. The more light you\nshine on it, the more it" );
assert( out[1] == "will contract." );

in = "Floccinaucinih ilipili-fication";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Floccinaucinih ilipili-\nfication" );

in = "Floccinaucinih ilipilification ";
formatText( in, 24, 4, out );
assert( out.size() == 1 );
assert( out[0] == "Floccinaucinih ilipilifi-\ncation" );

formatText( "123456 123456", 6, 4, out );
assert( out.size() == 1 );
assert( out[0] == "123456\n123456 " );

}
Oct 22 '07 #4
James Kanze <ja*********@gm ail.comwrote:
On Oct 22, 12:11 am, "Daniel T." <danie...@earth link.netwrote:
The function below does exactly what I want it to (there is a
main to test it as well.) However, I'm curious about ideas of
making it better. Anyone interested in critiquing it?

Well, just from the code, I have great difficulty even
understanding it. I'm not even sure what it is supposed to do.
That's why I posted it. I don't generally make functions with that high
a complexity and so I was wondering if someone could make some
suggestions on the logic to see if the complexity can be reduced.

As far as what it's supposed to do... It is supposed to pass all the
tests that were included. I.E., proper execution will exit normally, if
an assert fires, then there is a problem. (Note, due to Alf's helpful
critique I have modified one of the tests and added another.)
If you're trying to break up text into lines, I don't really
understand the output; what is each entry in the vector (since the
entries themselves have line breaks)?
Each entry in the vector is a page.
Without a specification of what the function is supposed to do, you
can't begin to write it, write a test for it, or ask anyone to
review it.
The function is supposed to take a string of text and break it up into a
number of pages. Each page is supposed to be no more than charsPerLine
wide and no more than lines high. The code must be able to hyphenate any
word wider than charsPerLine (although not necessarily at the proper
place according to English grammar,) and the function must be able to
recognize when a very long word is already hyphenated so it won't add
unnecessary hyphens.
Otherwise: in general, if the problem is breaking up text into
lines of a maximum width, with line breaks only at word boundaries
(or other specified places), then the usual solution would be to
break the problem up into parts: a class which breaks the input up
into words, and a class which puts the words into the destintation,
adding line breaks as needed.
Can you show me code demonstrating this? Would such code be less complex
than what I already have? I'm interested in reducing the cyclomatic
complexity if possible.
Oct 22 '07 #5
"Alf P. Steinbach" <al***@start.no wrote:
* Daniel T.:
"Alf P. Steinbach" <al***@start.no wrote:
* Daniel T. -Alf P. Steinbach:
The logic, however seems identical to mine. Can you think of any
improvements to the logic?
formatText( "123456 123456", 6, 4, result );
Thanks. Not only did it show an anomaly in the code, but it exposed an
error in one of the other tests! Still no ideas on reducing the
complexity of the code though?

That /was/ my idea for simplifying the code: should be much simpler if
you fix that.
I fixed that, but my fix didn't change the cyclomatic complexity...
I fail to see any changes in the formatText function (but then, I only
glanced at it, I presume you'd have explained it if you fixed it)?
The only thing I can think to change is that the function performs two
different jobs through the loop. It breaks the string up into lines, and
it breaks lines up into pages. I could seperate these two jobs into two
functions; "breakLines " and "breakPages ". Oh well, I have other
functions to write. Thanks for the help.
Oct 22 '07 #6
Daniel T. wrote:
James Kanze <ja*********@gm ail.comwrote:
>On Oct 22, 12:11 am, "Daniel T." <danie...@earth link.netwrote:
The function below does exactly what I want it to (there is a
main to test it as well.) However, I'm curious about ideas of
making it better. Anyone interested in critiquing it?

Well, just from the code, I have great difficulty even
understandin g it. I'm not even sure what it is supposed to do.

That's why I posted it. I don't generally make functions with that high
a complexity and so I was wondering if someone could make some
suggestions on the logic to see if the complexity can be reduced.

As far as what it's supposed to do... It is supposed to pass all the
tests that were included. I.E., proper execution will exit normally, if
an assert fires, then there is a problem. (Note, due to Alf's helpful
critique I have modified one of the tests and added another.)
You cannot really be serious. The following passes all the tests. Moreover,
the logic that makes is pass all the tests is very simple and easy to
understand. Nonetheless, I seriously doubt that it will satisfy you:
struct text : vector< string {
text & add ( string const & line ) {
push_back( line );
return ( *this );
}
};

struct arguments : pair< string, pair< int, int {
arguments( string const & line, int a, int b )
: pair< string, pair< int, int ( line, pair<int,int>(a ,b) )
{}
};

void formatText (
string const& in,
int charsPerLine,
int lines,
vector< string >& out )
{
map< arguments, text table;
table[ arguments( "hello", 24, 4 ) ]
.add( "hello" );
table[ arguments( "Put up with it and you will"
" get more of it.", 24, 4 ) ]
.add("Put up with it and you\nwill get more of it.");
table[ arguments( "The mind of a bigot is like the pupil"
" of the eye. The more light you shine"
" on it, the more it will contract.", 24, 4 ) ]
.add("The mind of a bigot is\nlike the pupil"
" of the\neye. The more light you\nshine"
" on it, the more it")
.add("will contract.");
table[ arguments( "Floccinaucinih ilipili-fication", 24, 4 ) ]
.add("Floccinau cinihilipili-\nfication");
table[ arguments( "Floccinaucinih ilipilification ", 24, 4 ) ]
.add("Floccinau cinihilipilifi-\ncation");
table[ arguments( "123456 123456", 6,4 ) ]
.add("123456\n1 23456");

text result = table[ arguments( in, charsPerLine, lines ) ];
out = result;
}

>If you're trying to break up text into lines, I don't really
understand the output; what is each entry in the vector (since the
entries themselves have line breaks)?

Each entry in the vector is a page.
>Without a specification of what the function is supposed to do, you
can't begin to write it, write a test for it, or ask anyone to
review it.

The function is supposed to take a string of text and break it up into a
number of pages. Each page is supposed to be no more than charsPerLine
wide and no more than lines high. The code must be able to hyphenate any
word wider than charsPerLine (although not necessarily at the proper
place according to English grammar,) and the function must be able to
recognize when a very long word is already hyphenated so it won't add
unnecessary hyphens.
Ah. Thanks. That helps.

I guess a first step to break up the complexity is to split the function in
two: one splits the text into lines, the next collates lines into pages.
Something like:

void split_into_line s ( string const & in,
unsigned int charsPerLine,
vector< string & out );

void collate_pages ( vector< string const & in,
unsigned int linesPerPage,
vector< string & out );
Then you'd have:

void formatText(
string const& in,
unsigned int charsPerLine,
unsigned int linesPerPage,
vector< string >& out ) {
vector< string lines;
split_into_line s( in, charsPerLine, lines );
collate_into_pa ges( lines, linesPerPage, out );
}
>Otherwise: in general, if the problem is breaking up text into
lines of a maximum width, with line breaks only at word boundaries
(or other specified places), then the usual solution would be to
break the problem up into parts: a class which breaks the input up
into words, and a class which puts the words into the destintation,
adding line breaks as needed.

Can you show me code demonstrating this? Would such code be less complex
than what I already have? I'm interested in reducing the cyclomatic
complexity if possible.
What is this cyclomatic complexity (and why is it bad)?
Best

Kai-Uwe Bux
Oct 22 '07 #7
"Alf P. Steinbach" <al***@start.no wrote:
I'm not sure, but in this equivalent expression of the function it seems
as if it might have a off-by-one bug.
That has me worried. I've hit the function with several tests but have
been unable to find any problems so far. Why do you feel there is an off
by one bug? Is there something specific, or is it just a gut feeling?
Oct 22 '07 #8
Kai-Uwe Bux <jk********@gmx .netwrote:
What is this cyclomatic complexity (and why is it bad)?
http://www.literateprogramming.com/mccabe.pdf
Oct 22 '07 #9
On 2007-10-22 13:38, Daniel T. wrote:
James Kanze <ja*********@gm ail.comwrote:
>On Oct 22, 12:11 am, "Daniel T." <danie...@earth link.netwrote:
Can you show me code demonstrating this? Would such code be less complex
than what I already have? I'm interested in reducing the cyclomatic
complexity if possible.
A bit off-topic but in my experience there is no benefit in reducing the
cyclomatic complexity just for the sake of reducing it. A toolthat
automatically calculates the cyclomatic complexity can be useful since
it helps you find functions that are *potentially* too complex. But each
function has to be evaluated by a human to determine if it is too
complex or not, i.e. a function with a large switch-statement will have
a high cyclomatic complexity but will not necessarily be very complex.

After a quick look at your function it looks like it would have a
cyclomatic complexity of about 5, which IMO is not very high.

BTW: you use the following to add a line-break: "out.back() +=
(char)0x0A;" but would it not be better to use "out.back() += '\n';" to
make the code more portable?

--
Erik Wikström
Oct 23 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

26
2928
by: Michael Strorm | last post by:
Hi! I posted a message a while back asking for project suggestions, and decided to go with the idea of creating an adventure game (although it was never intended to be a 'proper' game, rather an excuse to write- and learn- some C++). To cut a long story short, I wrote a fair chunk of it, but realised that it's... not very good. Okay, it's my first "proper" C++ program, so that's no big deal, but I don't want to waste more time working...
3
2286
by: Rv5 | last post by:
I have an assignment due mid next week that I have completed. I was hoping someone could take a look at the code and tell me what they think of the style. Id like to know if this is good code that I can be proud of or if my technique still needs some work. What can be improved? I created an htm page that first lists the assignment, and under that is my code. I think the code is good, but Ive thought that before... ...
19
2538
by: TC | last post by:
Are there any good sites or forums for a web critique? I went to alt.html.critique and it's pretty dead.
188
7169
by: christopher diggins | last post by:
I have posted a C# critique at http://www.heron-language.com/c-sharp-critique.html. To summarize I bring up the following issues : - unsafe code - attributes - garbage collection - non-deterministic destructors - Objects can't exist on the stack - Type / Reference Types
39
1920
by: Eric | last post by:
There is a VB.NET critique on the following page: http://www.vb7-critique.741.com/ for those who are interested. Feel free to take a look and share your thoughts. Cheers, Eric. Ps: for those on comp.programming, this may be off topic, but I've posted there because the critique was part of a discussion in that group.
61
3537
by: warint | last post by:
My lecturer gave us an assignment. He has a very "mature" way of teaching in that he doesn't care whether people show up, whether they do the assignments, or whether they copy other people's work. Furthermore, he doesn't even mark the assignments, but rather gives tips and so forth when going over students' work. To test students' capabilities for the purpose of state exams and qualifications though, he actually sits down with us at a...
7
1462
by: =?UTF-8?B?SXbDoW4gU8OhbmNoZXogT3J0ZWdh?= | last post by:
Mo wrote: Don't. If you need spacers in a table, do: echo "<td colspan='5'></td>"; You will compact your code and make it more legible if you just output everything from the beginning in those cases. There will be situations in
2
1112
by: winston | last post by:
I wrote a Python program (103 lines, below) to download developer data from SourceForge for research about social networks. Please critique the code and let me know how to improve it. An example use of the program: promptpython download.py 1 240000 The above command downloads data for the projects with IDs between 1
2
1314
by: matt | last post by:
this is my first program in this language ever (besides 'hello world'), can i get a code critique, please? it's purpose is to read through an input file character by character and tally the occurrence of each input character. it seems to compile and run, so i'm looking for the opinions of old-timers here plz. /* * File: occurrenceTally.cpp * Author: matthew *
0
8427
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8330
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8850
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8746
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
7355
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6178
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5649
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4175
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
2749
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.