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.

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


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

  1. my %hash;  
  2. @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):

  1. sub unique_mapping  
  2. {  
  3.  my @ar1 = ('a''b''c''d''e');  
  4.  my @ar2 = ('1''2''3''4''5');  
  5.    
  6.  print Dumper(\@ar1);  
  7.  print Dumper(\@ar2);  
  8.    
  9.  my %hash;  
  10.  @hash{@ar1} = (@ar2) x @ar1;  
  11.    
  12.    
  13.  print Dumper(\%hash);  
  14.    
  15. }  


Result:

  1. $VAR1 = [  
  2.           'a',  
  3.           'b',  
  4.           'c',  
  5.           'd',  
  6.           'e'  
  7.         ];  
  8. $VAR1 = [  
  9.           '1',  
  10.           '2',  
  11.           '3',  
  12.           '4',  
  13.           '5'  
  14.         ];  
  15. $VAR1 = {  
  16.           'e' => '5',  
  17.           'c' => '3',  
  18.           'a' => '1',  
  19.           'b' => '2',  
  20.           'd' => '4'  
  21.         };  


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

  1. sub keys_non_unique_mapping  
  2. {  
  3.  my @ar1 = ('a''b''b''d''e');  
  4.  my @ar2 = ('1''2''3''4''5');  
  5.    
  6.  print Dumper(\@ar1);  
  7.  print Dumper(\@ar2);  
  8.    
  9.  my %hash;  
  10.  @hash{@ar1} = (@ar2) x @ar1;  
  11.    
  12.    
  13.  print Dumper(\%hash);  
  14.    
  15. }  


Result:

  1. $VAR1 = [  
  2.           'a',  
  3.           'b',  
  4.           'b',  
  5.           'd',  
  6.           'e'  
  7.         ];  
  8. $VAR1 = [  
  9.           '1',  
  10.           '2',  
  11.           '3',  
  12.           '4',  
  13.           '5'  
  14.         ];  
  15. $VAR1 = {  
  16.           'e' => '5',  
  17.           'a' => '1',  
  18.           'b' => '3',  
  19.           'd' => '4'  
  20.         };  

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:

  1. use strict;  
  2.   
  3. my $log_file=file_string_here;  
  4.   
  5. my $LOG_HANDLE = open_log_file_for_writing($log_file);  
  6.   
  7. log_entry($LOG_HANDLE"Logging started");  
  8.   
  9. log_entry($LOG_HANDLE"Logging finished");  
  10.   
  11. close_log_file($LOG_HANDLE);  
  12.   
  13.   
  14. sub open_log_file_for_writing  
  15. {  
  16.    my $log_file = shift;  
  17.    my $LOGGING_HANDLE;  
  18.   
  19.    print "INFO Opening log file...\n";  
  20.   
  21.    unless(open $LOGGING_HANDLE">> "$log_file) {  
  22.       return undef;  
  23.    }  
  24.   
  25.    my $current_time = localtime;  
  26.    print $LOGGING_HANDLE "\n".$current_time."\n";  
  27.   
  28.    return $LOGGING_HANDLE;  
  29. }  
  30.   
  31. sub log_entry  
  32. {  
  33.    my $LOGGING_HANDLE = shift;  
  34.    my $log_entry      = shift;  
  35.   
  36.    print $LOGGING_HANDLE $log_entry."\n";  
  37. }  
  38.   
  39. sub close_log_file  
  40. {  
  41.    my $LOGGING_HANDLE = shift;  
  42.    print "INFO Closing log file...\n";  
  43.    close($LOGGING_HANDLE);  
  44. }  



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:

  1. my $g_LOGGING_HANDLE = open_log_file_for_writing($log_file);  
  2. log_entry("Logging started");  
  3.   
  4. sub log_entry  
  5. {  
  6.    my $log_entry      = shift;  
  7.   
  8.    print $g_LOGGING_HANDLE $log_entry."\n";  
  9. }  


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:

  1. my $LOG_ENABLED = 1; # put 1 to enable logging, 0 to disable logging  
  2.   
  3. my $log_file = "plugin_request.log";  
  4. ...  
  5.   
  6. my $g_LOGGING_HANDLE;  
  7. undef $g_LOGGING_HANDLE;  
  8.   
  9. if ($LOG_ENABLED)  
  10. {  
  11.    $g_LOGGING_HANDLE = open_log_file_for_writing($log_file);  
  12. }  
  13.   
  14.   
  15. ...  
  16.   
  17. sub log_entry  
  18. {  
  19.    my $log_entry      = shift;  
  20.   
  21.    return if (!defined($g_LOGGING_HANDLE));  
  22.   
  23.    print $g_LOGGING_HANDLE $log_entry."\n";  
  24. }  
  25.   
  26. sub close_log_file  
  27. {  
  28.    my $LOGGING_HANDLE = shift;  
  29.   
  30.    return if (!defined($g_LOGGING_HANDLE));  
  31.   
  32.    print "INFO Closing log file...\n";  
  33.    close($LOGGING_HANDLE);  
  34. }  

Friday, September 11, 2009

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

Suppose we have implemented the following scenario:

  1. // read input file line by line  
  2. // allocate 256 characters for each line  
  3.   
  4. ifstream input_file("some_file.txt");  
  5. const int BUF_SIZE=256;  
  6. char buf[BUF_SIZE];  
  7. string s, strCurString;  
  8.   
  9. if (!input_file.is_open())  
  10. {  
  11.    cerr << "File some_file.txt coudl not be open!" << endl;  
  12.    getch();  
  13.    exit(EXIT_FAILURE);  
  14. }  
  15.   
  16. while(!input_file.eof()) {  
  17.    input_file.getline(buf, BUF_SIZE);  
  18.    strCurString = buf;  
  19.    s += strCurString;  
  20. }  
  21.   
  22. 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:

  1. // read input file line by line  
  2. // allocate 256 characters for each line  
  3.   
  4. ifstream input_file("some_file.txt");  
  5. const int BUF_SIZE=256;  
  6. char buf[BUF_SIZE];  
  7. string s, strCurString;  
  8.   
  9. if (!input_file.is_open())  
  10. {  
  11.    cerr << "File some_file.txt coudl not be open!" << endl;  
  12.    getch();  
  13.    exit(EXIT_FAILURE);  
  14. }  
  15.   
  16. while(!input_file.eof()) {  
  17.    input_file.getline(buf, BUF_SIZE);  
  18.   
  19.    // remember about failbit when amount of  
  20.    // characters in the current line is  
  21.    // more than BUF_SIZE  
  22.    if (input_file.fail() && !input_file.eof())  
  23.        // clear up the failbit and   
  24.        // continue reading the input file  
  25.       input_file.clear();  
  26.    strCurString = buf;  
  27.    s += strCurString;  
  28. }  
  29.   
  30. cout << "File contents: " << endl << s << endl;