LCOV - code coverage report
Current view: top level - tools - h36.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 98 141 69.5 %
Date: 2026-11-05 10:19:04 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      114744 : digits_upper() {
      62      114744 :   return "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      63             : }
      64             : 
      65             : static
      66             : const char*
      67       11773 : digits_lower() {
      68       11773 :   return "0123456789abcdefghijklmnopqrstuvwxyz";
      69             : }
      70             : 
      71             : static
      72             : const char*
      73           0 : value_out_of_range() {
      74           0 :   return "value out of range.";
      75             : }
      76             : 
      77             : static
      78           2 : const char* invalid_number_literal() {
      79           2 :   return "invalid number literal.";
      80             : }
      81             : 
      82             : static
      83           0 : const char* unsupported_width() {
      84           0 :   return "unsupported width.";
      85             : }
      86             : 
      87             : static
      88             : void
      89           0 : fill_with_stars(unsigned width, char* result) {
      90           0 :   while (width) {
      91           0 :     *result++ = '*';
      92           0 :     width--;
      93             :   }
      94           0 :   *result = '\0';
      95           0 : }
      96             : 
      97             : static
      98             : void
      99      102973 : encode_pure(
     100             :   const char* digits,
     101             :   unsigned digits_size,
     102             :   unsigned width,
     103             :   int value,
     104             :   char* result) {
     105             :   char buf[16];
     106             :   int rest;
     107             :   unsigned i, j;
     108             :   i = 0;
     109             :   j = 0;
     110      102973 :   if (value < 0) {
     111             :     j = 1;
     112           0 :     value = -value;
     113             :   }
     114             :   while (1) {
     115      493908 :     rest = value / digits_size;
     116      493908 :     buf[i++] = digits[value - rest * digits_size];
     117      493908 :     if (rest == 0) {
     118             :       break;
     119             :     }
     120             :     value = rest;
     121             :   }
     122      102973 :   if (j) {
     123           0 :     buf[i++] = '-';
     124             :   }
     125      123929 :   for(j=i; j<width; j++) {
     126       20956 :     *result++ = ' ';
     127             :   }
     128      596881 :   while (i != 0) {
     129      493908 :     *result++ = buf[--i];
     130             :   }
     131      102973 :   *result = '\0';
     132      102973 : }
     133             : 
     134             : static
     135             : const char*
     136     1009816 : decode_pure(
     137             :   const int* digits_values,
     138             :   const unsigned digits_size,
     139             :   const char* s,
     140             :   const unsigned s_size,
     141             :   int* result) {
     142             :   int si, dv;
     143             :   int have_minus = 0;
     144             :   int have_non_blank = 0;
     145             :   int value = 0;
     146             :   unsigned i = 0;
     147     5553987 :   for(; i<s_size; i++) {
     148             :     // go through unsigned char: plain char is signed on some platforms and unsigned on others
     149     4544172 :     si = static_cast<unsigned char>(s[i]);
     150     4544172 :     if (si > 127) {
     151           0 :       *result = 0;
     152           0 :       return invalid_number_literal();
     153             :     }
     154     4544172 :     if (si == ' ') {
     155     1432855 :       if (!have_non_blank) {
     156     1432855 :         continue;
     157             :       }
     158           0 :       value *= digits_size;
     159     3111317 :     } else if (si == '-') {
     160        1138 :       if (have_non_blank) {
     161           0 :         *result = 0;
     162           0 :         return invalid_number_literal();
     163             :       }
     164             :       have_non_blank = 1;
     165             :       have_minus = 1;
     166        1138 :       continue;
     167             :     } else {
     168             :       have_non_blank = 1;
     169     3110179 :       dv = digits_values[si];
     170     3110179 :       if (dv < 0 || dv >= static_cast<int>(digits_size)) {
     171           1 :         *result = 0;
     172           1 :         return invalid_number_literal();
     173             :       }
     174     3110178 :       value *= digits_size;
     175     3110178 :       value += dv;
     176             :     }
     177             :   }
     178     1009815 :   if (have_minus) {
     179        1138 :     value = -value;
     180             :   }
     181     1009815 :   *result = value;
     182     1009815 :   return 0;
     183             : }
     184             : 
     185             : /*! hybrid-36 encoder: converts integer value to string result
     186             : 
     187             :       width: must be 4 (e.g. for residue sequence numbers)
     188             :                   or 5 (e.g. for atom serial numbers)
     189             : 
     190             :       value: integer value to be converted
     191             : 
     192             :       result: pointer to char array of size width+1 or greater
     193             :               on return result is null-terminated
     194             : 
     195             :       return value: pointer to error message, if any,
     196             :                     or 0 on success
     197             : 
     198             :     Example usage (from C++):
     199             :       char result[4+1];
     200             :       const char* errmsg = hy36encode(4, 12345, result);
     201             :       if (errmsg) throw std::runtime_error(errmsg);
     202             :  */
     203             : const char*
     204      102973 : hy36encode(unsigned width, int value, char* result) {
     205             :   int i = value;
     206      102973 :   if (width == 4U) {
     207           1 :     if (i >= -999) {
     208           1 :       if (i < 10000) {
     209           0 :         encode_pure(digits_upper(), 10U, 4U, i, result);
     210           0 :         return 0;
     211             :       }
     212           1 :       i -= 10000;
     213           1 :       if (i < 1213056 /* 26*36**3 */) {
     214           1 :         i += 466560 /* 10*36**3 */;
     215           1 :         encode_pure(digits_upper(), 36U, 0U, i, result);
     216           1 :         return 0;
     217             :       }
     218           0 :       i -= 1213056;
     219           0 :       if (i < 1213056) {
     220           0 :         i += 466560;
     221           0 :         encode_pure(digits_lower(), 36U, 0U, i, result);
     222           0 :         return 0;
     223             :       }
     224             :     }
     225      102972 :   } else if (width == 5U) {
     226      102972 :     if (i >= -9999) {
     227      102972 :       if (i < 100000) {
     228      102859 :         encode_pure(digits_upper(), 10U, 5U, i, result);
     229      102859 :         return 0;
     230             :       }
     231         113 :       i -= 100000;
     232         113 :       if (i < 43670016 /* 26*36**4 */) {
     233         112 :         i += 16796160 /* 10*36**4 */;
     234         112 :         encode_pure(digits_upper(), 36U, 0U, i, result);
     235         112 :         return 0;
     236             :       }
     237           1 :       i -= 43670016;
     238           1 :       if (i < 43670016) {
     239           1 :         i += 16796160;
     240           1 :         encode_pure(digits_lower(), 36U, 0U, i, result);
     241           1 :         return 0;
     242             :       }
     243             :     }
     244             :   } else {
     245           0 :     fill_with_stars(width, result);
     246           0 :     return unsupported_width();
     247             :   }
     248           0 :   fill_with_stars(width, result);
     249           0 :   return value_out_of_range();
     250             : }
     251             : 
     252             : /*! hybrid-36 decoder: converts string s to integer result
     253             : 
     254             :       width: must be 4 (e.g. for residue sequence numbers)
     255             :                   or 5 (e.g. for atom serial numbers)
     256             : 
     257             :       s: string to be converted
     258             :          does not have to be null-terminated
     259             : 
     260             :       s_size: size of s
     261             :               must be equal to width, or an error message is
     262             :               returned otherwise
     263             : 
     264             :       result: integer holding the conversion result
     265             : 
     266             :       return value: pointer to error message, if any,
     267             :                     or 0 on success
     268             : 
     269             :     Example usage (from C++):
     270             :       int result;
     271             :       const char* errmsg = hy36decode(width, "A1T5", 4, &result);
     272             :       if (errmsg) throw std::runtime_error(errmsg);
     273             :  */
     274             : const char*
     275     1009816 : hy36decode(unsigned width, const char* s, unsigned s_size, int* result) {
     276         327 :   static const std::vector<int> digits_values_upper_vector([]() {
     277         327 :     std::vector<int> ret(128U,-1);
     278       12099 :     for(unsigned i=0; i<36U; i++) {
     279       11772 :       int di = static_cast<unsigned char>(digits_upper()[i]);
     280       11772 :       if (di > 127) {
     281           0 :         plumed_error()<<"internal error hy36decode: integer value out of range";
     282             :       }
     283       11772 :       ret[di] = i;
     284             :     }
     285         327 :     return ret;
     286             :   }
     287     1009816 :   ());
     288     1009816 :   static const int* digits_values_upper=digits_values_upper_vector.data();
     289         327 :   static const std::vector<int> digits_values_lower_vector([]() {
     290         327 :     std::vector<int> ret(128U,-1);
     291       12099 :     for(unsigned i=0; i<36U; i++) {
     292       11772 :       int di = static_cast<unsigned char>(digits_lower()[i]);
     293       11772 :       if (di > 127) {
     294           0 :         plumed_error()<<"internal error hy36decode: integer value out of range";
     295             :       }
     296       11772 :       ret[di] = i;
     297             :     }
     298         327 :     return ret;
     299             :   }
     300     1009816 :   ());
     301     1009816 :   static const int* digits_values_lower=digits_values_lower_vector.data();
     302             :   int di;
     303             :   const char* errmsg;
     304     1009816 :   if (s_size == width) {
     305     1009816 :     di = static_cast<unsigned char>(s[0]);
     306     1009816 :     if (di <= 127) {
     307     1009816 :       if (digits_values_upper[di] >= 10) {
     308          14 :         errmsg = decode_pure(digits_values_upper, 36U, s, s_size, result);
     309          14 :         if (errmsg == 0) {
     310             :           /* result - 10*36**(width-1) + 10**width */
     311          13 :           if      (width == 4U) {
     312           7 :             (*result) -= 456560;
     313           6 :           } else if (width == 5U) {
     314           6 :             (*result) -= 16696160;
     315             :           } else {
     316           0 :             *result = 0;
     317           0 :             return unsupported_width();
     318             :           }
     319          13 :           return 0;
     320             :         }
     321     1009802 :       } else if (digits_values_lower[di] >= 10) {
     322           0 :         errmsg = decode_pure(digits_values_lower, 36U, s, s_size, result);
     323           0 :         if (errmsg == 0) {
     324             :           /* result + 16*36**(width-1) + 10**width */
     325           0 :           if      (width == 4U) {
     326           0 :             (*result) += 756496;
     327           0 :           } else if (width == 5U) {
     328           0 :             (*result) += 26973856;
     329             :           } else {
     330           0 :             *result = 0;
     331           0 :             return unsupported_width();
     332             :           }
     333           0 :           return 0;
     334             :         }
     335             :       } else {
     336     1009802 :         errmsg = decode_pure(digits_values_upper, 10U, s, s_size, result);
     337     1009802 :         if (errmsg) {
     338             :           return errmsg;
     339             :         }
     340     1009802 :         if (!(width == 4U || width == 5U)) {
     341           0 :           *result = 0;
     342           0 :           return unsupported_width();
     343             :         }
     344             :         return 0;
     345             :       }
     346             :     }
     347             :   }
     348           1 :   *result = 0;
     349           1 :   return invalid_number_literal();
     350             : }
     351             : 
     352             : }
     353             : 
     354             : }
     355             : 

Generated by: LCOV version 1.16