Wednesday, September 16, 2009

Sting's programmer's mind

First impression of Sting's web-site is his quote of the day:

"I quite like using songs as a modular system where you can mix and match lines from different songs. It's a tradition now and people expect it. Basically, it's all one big song. You could say it was an aspect of postmodernism if you liked but you'd be called pretentious if you said that."

Perl: concise way to map one array onto antother in perl hash

Suppose I have two arrays. Suppose further elements in one of this array logically map onto elements of the other.


my @ar1 = (...);
my @ar2 = (...);


Easy way to map ar1 (keys) onto ar2 in perl is:


my %hash;
@hash{@ar1} = (@ar2) x @ar1;


Important assumption: the order in this two arrays matters. In other words first element of ar1 maps to first element of ar2, ..., n-th element of first array ar1 maps onto n-th element of ar2 and there exactly n elements in both arrays.


Examples

It is OK to have unique keys, obviously for the hash to preserve correct mapping (include use Data::Dumper in your code):


sub unique_mapping
{
my @ar1 = ('a', 'b', 'c', 'd', 'e');
my @ar2 = ('1', '2', '3', '4', '5');

print Dumper(\@ar1);
print Dumper(\@ar2);

my %hash;
@hash{@ar1} = (@ar2) x @ar1;


print Dumper(\%hash);

}


Result:


$VAR1 = [
'a',
'b',
'c',
'd',
'e'
];
$VAR1 = [
'1',
'2',
'3',
'4',
'5'
];
$VAR1 = {
'e' => '5',
'c' => '3',
'a' => '1',
'b' => '2',
'd' => '4'
};


The mapping is not what you might want to have in the case when keys are not unique:


sub keys_non_unique_mapping
{
my @ar1 = ('a', 'b', 'b', 'd', 'e');
my @ar2 = ('1', '2', '3', '4', '5');

print Dumper(\@ar1);
print Dumper(\@ar2);

my %hash;
@hash{@ar1} = (@ar2) x @ar1;


print Dumper(\%hash);

}


Result:


$VAR1 = [
'a',
'b',
'b',
'd',
'e'
];
$VAR1 = [
'1',
'2',
'3',
'4',
'5'
];
$VAR1 = {
'e' => '5',
'a' => '1',
'b' => '3',
'd' => '4'
};

Monday, September 14, 2009

Logging: helpful perl snippet to start with

I needed to establish simple logging in my small perl app which serves as a plugin for a company "big" product. Here is what I have come up with:


use strict;

my $log_file=file_string_here;

my $LOG_HANDLE = open_log_file_for_writing($log_file);

log_entry($LOG_HANDLE, "Logging started");

log_entry($LOG_HANDLE, "Logging finished");

close_log_file($LOG_HANDLE);


sub open_log_file_for_writing
{
my $log_file = shift;
my $LOGGING_HANDLE;

print "INFO Opening log file...\n";

unless(open $LOGGING_HANDLE, ">> ", $log_file) {
return undef;
}

my $current_time = localtime;
print $LOGGING_HANDLE "\n".$current_time."\n";

return $LOGGING_HANDLE;
}

sub log_entry
{
my $LOGGING_HANDLE = shift;
my $log_entry = shift;

print $LOGGING_HANDLE $log_entry."\n";
}

sub close_log_file
{
my $LOGGING_HANDLE = shift;
print "INFO Closing log file...\n";
close($LOGGING_HANDLE);
}




upd: the logging handle can be externalized for easing the use of the logging. It comes at cost of global variable, but might still suit moderately sized perl-scripts. Code will change a bit:


my $g_LOGGING_HANDLE = open_log_file_for_writing($log_file);
log_entry("Logging started");

sub log_entry
{
my $log_entry = shift;

print $g_LOGGING_HANDLE $log_entry."\n";
}


Now you can call log("log entry goes here") from where you want quickly, without the need to pass down as well the logging handle, for example deep inside some procedure or function.

upd1: If you want to control whether to log or not, another small modification will do it for you:


my $LOG_ENABLED = 1; # put 1 to enable logging, 0 to disable logging

my $log_file = "plugin_request.log";
...

my $g_LOGGING_HANDLE;
undef $g_LOGGING_HANDLE;

if ($LOG_ENABLED)
{
$g_LOGGING_HANDLE = open_log_file_for_writing($log_file);
}


...

sub log_entry
{
my $log_entry = shift;

return if (!defined($g_LOGGING_HANDLE));

print $g_LOGGING_HANDLE $log_entry."\n";
}

sub close_log_file
{
my $LOGGING_HANDLE = shift;

return if (!defined($g_LOGGING_HANDLE));

print "INFO Closing log file...\n";
close($LOGGING_HANDLE);
}

Friday, September 11, 2009

C++: if file line length exceeds array (buffer) length

Suppose we have implemented the following scenario:


// read input file line by line
// allocate 256 characters for each line

ifstream input_file("some_file.txt");
const int BUF_SIZE=256;
char buf[BUF_SIZE];
string s, strCurString;

if (!input_file.is_open())
{
cerr << "File some_file.txt coudl not be open!" << endl;
getch();
exit(EXIT_FAILURE);
}

while(!input_file.eof()) {
input_file.getline(buf, BUF_SIZE);
strCurString = buf;
s += strCurString;
}

cout << "File contents: " << endl << s << endl;


But what if the current file length exceeds BUF_SIZE? Well, in this case the while loop will never end, becoming an infinite loop. Why? Simply, because in the input file stream object a special bit (failbit) will be set, saying that the last getline() operation has failed (in this case not due to the end of a file, but due to the buffer length exceeding). In this case all subsequent calls to getline() will fail to read anything (can be seen by calling input_file.gcount(), which constantly returns 0 (zero) after the last getline() call that led to setting a failbit).


To overcome this, we can use a trick found here:


// read input file line by line
// allocate 256 characters for each line

ifstream input_file("some_file.txt");
const int BUF_SIZE=256;
char buf[BUF_SIZE];
string s, strCurString;

if (!input_file.is_open())
{
cerr << "File some_file.txt coudl not be open!" << endl;
getch();
exit(EXIT_FAILURE);
}

while(!input_file.eof()) {
input_file.getline(buf, BUF_SIZE);

// remember about failbit when amount of
// characters in the current line is
// more than BUF_SIZE
if (input_file.fail() && !input_file.eof())
// clear up the failbit and
// continue reading the input file
input_file.clear();
strCurString = buf;
s += strCurString;
}

cout << "File contents: " << endl << s << endl;