LCOV - code coverage report
Current view: top level - tools - h36.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 87 127 68.5 %
Date: 2024-10-18 14:00:25 Functions: 9 12 75.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2018-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "h36.h"
      23             : #include <vector>
      24             : #include "Exception.h"
      25             : 
      26             : namespace PLMD {
      27             : 
      28             : /// Tiny namespace for hybrid36 format.
      29             : /// This namespace includes freely available tools for h36 format.
      30             : namespace h36 {
      31             : 
      32             : 
      33             : /*! C port of the hy36encode() and hy36decode() functions in the
      34             :     hybrid_36.py Python prototype/reference implementation.
      35             :     See the Python script for more information.
      36             : 
      37             :     This file has no external dependencies, NOT even standard C headers.
      38             :     Optionally, use hybrid_36_c.h, or simply copy the declarations
      39             :     into your code.
      40             : 
      41             :     This file is unrestricted Open Source (cctbx.sf.net).
      42             :     Please send corrections and enhancements to cctbx@cci.lbl.gov .
      43             : 
      44             :     See also: http://cci.lbl.gov/hybrid_36/
      45             : 
      46             :     Ralf W. Grosse-Kunstleve, Feb 2007.
      47             :  */
      48             : 
      49             : /* The following #include may be commented out.
      50             :    It is here only to enforce consistency of the declarations
      51             :    and the definitions.
      52             :  */
      53             : // #include <iotbx/pdb/hybrid_36_c.h>
      54             : 
      55             : /* All static functions below are implementation details
      56             :    (and not accessible from other translation units).
      57             :  */
      58             : 
      59             : static
      60             : const char*
      61      110928 : digits_upper() { return "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
      62             : 
      63             : static
      64             : const char*
      65        8677 : digits_lower() { return "0123456789abcdefghijklmnopqrstuvwxyz"; }
      66             : 
      67             : static
      68             : const char*
      69           0 : value_out_of_range() { return "value out of range."; }
      70             : 
      71             : static
      72           2 : const char* invalid_number_literal() { return "invalid number literal."; }
      73             : 
      74             : static
      75           0 : const char* unsupported_width() { return "unsupported width."; }
      76             : 
      77             : static
      78             : void
      79           0 : fill_with_stars(unsigned width, char* result)
      80             : {
      81           0 :   while (width) {
      82           0 :     *result++ = '*';
      83           0 :     width--;
      84             :   }
      85           0 :   *result = '\0';
      86           0 : }
      87             : 
      88             : static
      89             : void
      90      102253 : encode_pure(
      91             :   const char* digits,
      92             :   unsigned digits_size,
      93             :   unsigned width,
      94             :   int value,
      95             :   char* result)
      96             : {
      97             :   char buf[16];
      98             :   int rest;
      99             :   unsigned i, j;
     100             :   i = 0;
     101             :   j = 0;
     102      102253 :   if (value < 0) {
     103             :     j = 1;
     104           0 :     value = -value;
     105             :   }
     106             :   while (1) {
     107      492778 :     rest = value / digits_size;
     108      492778 :     buf[i++] = digits[value - rest * digits_size];
     109      492778 :     if (rest == 0) break;
     110             :     value = rest;
     111             :   }
     112      102253 :   if (j) buf[i++] = '-';
     113      120739 :   for(j=i; j<width; j++) *result++ = ' ';
     114      595031 :   while (i != 0) *result++ = buf[--i];
     115      102253 :   *result = '\0';
     116      102253 : }
     117             : 
     118             : static
     119             : const char*
     120      893912 : decode_pure(
     121             :   const int* digits_values,
     122             :   unsigned digits_size,
     123             :   const char* s,
     124             :   unsigned s_size,
     125             :   int* result)
     126             : {
     127             :   int si, dv;
     128             :   int have_minus = 0;
     129             :   int have_non_blank = 0;
     130             :   int value = 0;
     131             :   unsigned i = 0;
     132     4916515 :   for(; i<s_size; i++) {
     133     4022604 :     si = s[i];
     134     4022604 :     if (si < 0 || si > 127) {
     135           0 :       *result = 0;
     136           0 :       return invalid_number_literal();
     137             :     }
     138     4022604 :     if (si == ' ') {
     139     1208661 :       if (!have_non_blank) continue;
     140           0 :       value *= digits_size;
     141             :     }
     142     2813943 :     else if (si == '-') {
     143           0 :       if (have_non_blank) {
     144           0 :         *result = 0;
     145           0 :         return invalid_number_literal();
     146             :       }
     147             :       have_non_blank = 1;
     148             :       have_minus = 1;
     149           0 :       continue;
     150             :     }
     151             :     else {
     152             :       have_non_blank = 1;
     153     2813943 :       dv = digits_values[si];
     154     2813943 :       if (dv < 0 || dv >= digits_size) {
     155           1 :         *result = 0;
     156           1 :         return invalid_number_literal();
     157             :       }
     158     2813942 :       value *= digits_size;
     159     2813942 :       value += dv;
     160             :     }
     161             :   }
     162      893911 :   if (have_minus) value = -value;
     163      893911 :   *result = value;
     164      893911 :   return 0;
     165             : }
     166             : 
     167             : /*! hybrid-36 encoder: converts integer value to string result
     168             : 
     169             :       width: must be 4 (e.g. for residue sequence numbers)
     170             :                   or 5 (e.g. for atom serial numbers)
     171             : 
     172             :       value: integer value to be converted
     173             : 
     174             :       result: pointer to char array of size width+1 or greater
     175             :               on return result is null-terminated
     176             : 
     177             :       return value: pointer to error message, if any,
     178             :                     or 0 on success
     179             : 
     180             :     Example usage (from C++):
     181             :       char result[4+1];
     182             :       const char* errmsg = hy36encode(4, 12345, result);
     183             :       if (errmsg) throw std::runtime_error(errmsg);
     184             :  */
     185             : const char*
     186      102253 : hy36encode(unsigned width, int value, char* result)
     187             : {
     188             :   int i = value;
     189      102253 :   if (width == 4U) {
     190           1 :     if (i >= -999) {
     191           1 :       if (i < 10000) {
     192           0 :         encode_pure(digits_upper(), 10U, 4U, i, result);
     193           0 :         return 0;
     194             :       }
     195           1 :       i -= 10000;
     196           1 :       if (i < 1213056 /* 26*36**3 */) {
     197           1 :         i += 466560 /* 10*36**3 */;
     198           1 :         encode_pure(digits_upper(), 36U, 0U, i, result);
     199           1 :         return 0;
     200             :       }
     201           0 :       i -= 1213056;
     202           0 :       if (i < 1213056) {
     203           0 :         i += 466560;
     204           0 :         encode_pure(digits_lower(), 36U, 0U, i, result);
     205           0 :         return 0;
     206             :       }
     207             :     }
     208             :   }
     209      102252 :   else if (width == 5U) {
     210      102252 :     if (i >= -9999) {
     211      102252 :       if (i < 100000) {
     212      102143 :         encode_pure(digits_upper(), 10U, 5U, i, result);
     213      102143 :         return 0;
     214             :       }
     215         109 :       i -= 100000;
     216         109 :       if (i < 43670016 /* 26*36**4 */) {
     217         108 :         i += 16796160 /* 10*36**4 */;
     218         108 :         encode_pure(digits_upper(), 36U, 0U, i, result);
     219         108 :         return 0;
     220             :       }
     221           1 :       i -= 43670016;
     222           1 :       if (i < 43670016) {
     223           1 :         i += 16796160;
     224           1 :         encode_pure(digits_lower(), 36U, 0U, i, result);
     225           1 :         return 0;
     226             :       }
     227             :     }
     228             :   }
     229             :   else {
     230           0 :     fill_with_stars(width, result);
     231           0 :     return unsupported_width();
     232             :   }
     233           0 :   fill_with_stars(width, result);
     234           0 :   return value_out_of_range();
     235             : }
     236             : 
     237             : /*! hybrid-36 decoder: converts string s to integer result
     238             : 
     239             :       width: must be 4 (e.g. for residue sequence numbers)
     240             :                   or 5 (e.g. for atom serial numbers)
     241             : 
     242             :       s: string to be converted
     243             :          does not have to be null-terminated
     244             : 
     245             :       s_size: size of s
     246             :               must be equal to width, or an error message is
     247             :               returned otherwise
     248             : 
     249             :       result: integer holding the conversion result
     250             : 
     251             :       return value: pointer to error message, if any,
     252             :                     or 0 on success
     253             : 
     254             :     Example usage (from C++):
     255             :       int result;
     256             :       const char* errmsg = hy36decode(width, "A1T5", 4, &result);
     257             :       if (errmsg) throw std::runtime_error(errmsg);
     258             :  */
     259             : const char*
     260      893912 : hy36decode(unsigned width, const char* s, unsigned s_size, int* result)
     261             : {
     262         241 :   static const std::vector<int> digits_values_upper_vector([]() {
     263         241 :     std::vector<int> ret(128U,-1);
     264        8917 :     for(unsigned i=0; i<36U; i++) {
     265        8676 :       int di = digits_upper()[i];
     266        8676 :       if (di < 0 || di > 127) {
     267           0 :         plumed_error()<<"internal error hy36decode: integer value out of range";
     268             :       }
     269        8676 :       ret[di] = i;
     270             :     }
     271         241 :     return ret;
     272      893912 :   }());
     273      893912 :   static const int* digits_values_upper=digits_values_upper_vector.data();
     274         241 :   static const std::vector<int> digits_values_lower_vector([]() {
     275         241 :     std::vector<int> ret(128U,-1);
     276        8917 :     for(unsigned i=0; i<36U; i++) {
     277        8676 :       int di = digits_lower()[i];
     278        8676 :       if (di < 0 || di > 127) {
     279           0 :         plumed_error()<<"internal error hy36decode: integer value out of range";
     280             :       }
     281        8676 :       ret[di] = i;
     282             :     }
     283         241 :     return ret;
     284      893912 :   }());
     285      893912 :   static const int* digits_values_lower=digits_values_lower_vector.data();
     286             :   int di;
     287             :   const char* errmsg;
     288      893912 :   if (s_size == width) {
     289      893912 :     di = s[0];
     290      893912 :     if (di >= 0 && di <= 127) {
     291      893912 :       if (digits_values_upper[di] >= 10) {
     292          14 :         errmsg = decode_pure(digits_values_upper, 36U, s, s_size, result);
     293          14 :         if (errmsg == 0) {
     294             :           /* result - 10*36**(width-1) + 10**width */
     295          13 :           if      (width == 4U) (*result) -= 456560;
     296           6 :           else if (width == 5U) (*result) -= 16696160;
     297             :           else {
     298           0 :             *result = 0;
     299           0 :             return unsupported_width();
     300             :           }
     301          13 :           return 0;
     302             :         }
     303             :       }
     304      893898 :       else if (digits_values_lower[di] >= 10) {
     305           0 :         errmsg = decode_pure(digits_values_lower, 36U, s, s_size, result);
     306           0 :         if (errmsg == 0) {
     307             :           /* result + 16*36**(width-1) + 10**width */
     308           0 :           if      (width == 4U) (*result) += 756496;
     309           0 :           else if (width == 5U) (*result) += 26973856;
     310             :           else {
     311           0 :             *result = 0;
     312           0 :             return unsupported_width();
     313             :           }
     314           0 :           return 0;
     315             :         }
     316             :       }
     317             :       else {
     318      893898 :         errmsg = decode_pure(digits_values_upper, 10U, s, s_size, result);
     319      893898 :         if (errmsg) return errmsg;
     320      893898 :         if (!(width == 4U || width == 5U)) {
     321           0 :           *result = 0;
     322           0 :           return unsupported_width();
     323             :         }
     324             :         return 0;
     325             :       }
     326             :     }
     327             :   }
     328           1 :   *result = 0;
     329           1 :   return invalid_number_literal();
     330             : }
     331             : 
     332             : }
     333             : 
     334             : }
     335             : 

Generated by: LCOV version 1.16