Changeset 558:c2ed1257b5b0

Show
Ignore:
Timestamp:
06/01/08 17:43:58 (7 months ago)
Author:
David Anderson <dave@…>
Branch:
default
Message:

Reimplement atou32 and atos32 to be faster and slightly more correct.

The implementation still has issues, notably with overflow detection.
Currently my opinion is that, if asm is needed to fix this, then it
shouldn't be fixed until it's really a problem for us.

Location:
nxos
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • nxos/base/lib/rcmd/_rcmd.c

    r556 r558  
    5858  S32 speeds[NXT_N_MOTORS]; 
    5959  U32 durations[NXT_N_MOTORS]; 
     60  bool success; 
    6061 
    6162  nx__rcmd_tokenize(line, RCMD_TOKEN_SEPARATOR, &ntokens, indices); 
     
    8283  for (i=0; i<NXT_N_MOTORS; i++) { 
    8384    if (ntokens <= i) { 
    84       speeds[i] = atos32(spec + subind[ntokens-1]); 
     85      success = atos32(spec + subind[ntokens-1], &speeds[i]); 
    8586    } else { 
    86       speeds[i] = atos32(spec + subind[i]); 
    87     } 
    88  
    89     if (speeds[i] > 100 || speeds[i] < -100) { 
     87      success = atos32(spec + subind[i], &speeds[i]); 
     88    } 
     89 
     90    if (!success || speeds[i] > 100 || speeds[i] < -100) { 
    9091      return RCMD_ERR_INVALID_PARAMETER; 
    9192    } 
     
    9798  for (i=0; i<NXT_N_MOTORS; i++) { 
    9899    if (ntokens <= i) { 
    99       durations[i] = atou32(spec + subind[ntokens-1]); 
     100      success = atou32(spec + subind[ntokens-1], &durations[i]); 
    100101    } else { 
    101       durations[i] = atou32(spec + subind[i]); 
    102     } 
    103  
    104     if (speeds[i] != 0 && durations[i] == 0) { 
     102      success = atou32(spec + subind[i], &durations[i]); 
     103    } 
     104 
     105    if (!success || (speeds[i] != 0 && durations[i] == 0)) { 
    105106      return RCMD_ERR_INVALID_PARAMETER; 
    106107    } 
     
    157158  } 
    158159 
    159   freq = atou32(line + indices[1]); 
    160   duration = atou32(line + indices[2]); 
    161  
    162   if (freq == 0 || duration == 0) { 
     160  if (!atou32(line + indices[1], &freq) || freq < 200 || 
     161      !atou32(line + indices[2], &duration) || duration < 100) { 
    163162    return RCMD_ERR_INVALID_PARAMETER; 
    164163  } 
     
    203202  } 
    204203 
    205   wait = atou32(line + indices[1]); 
    206   if (wait == 0) { 
     204  if (!atou32(line + indices[1], &wait) || wait == 0) { 
    207205    return RCMD_ERR_INVALID_PARAMETER; 
    208206  } 
  • nxos/base/util.c

    r557 r558  
    9494} 
    9595 
    96 U32 atou32(const char *s) { 
    97   U32 len, res = 0, i = 1; 
     96bool atou32(const char *s, U32* result) { 
     97  U32 prev = 0; 
    9898 
    99   len = strlen(s); 
    100   if (len == 0 || len > 10) { 
    101     return 0; 
     99  NX_ASSERT(s != NULL && result != NULL); 
     100 
     101  *result = 0; 
     102 
     103  // Skip leading zeros 
     104  while (*s && *s == '0') 
     105    s++; 
     106 
     107  for (; *s; s++) { 
     108    // Return 0 on invalid characters. 
     109    if (*s < '0' || *s > '9') 
     110      return FALSE; 
     111 
     112    *result = (10 * *result) + (*s - '0'); 
     113    // Naive overflow check. We could do better in pure asm by 
     114    // checking the ALU flags. 
     115    if (*result < prev) 
     116      return FALSE; 
     117 
     118    prev = *result; 
    102119  } 
    103120 
    104   for (; len>0; len--) { 
    105     char c = s[len-1]; 
     121  return TRUE; 
     122} 
    106123 
    107     /* If one character is invalid, fail by returning 0. */ 
    108     if (c < '0' || c > '9') { 
    109       return 0; 
    110     } 
     124bool atos32(const char *s, S32 *result) { 
     125  S32 prev = 0; 
     126  bool negative = FALSE; 
    111127 
    112     res += (c - '0') * i; 
    113     i *= 10; 
     128  NX_ASSERT(s != NULL && result != NULL); 
     129 
     130  *result = 0; 
     131 
     132  if (*s == '-') { 
     133    negative = TRUE; 
     134    s++; 
    114135  } 
    115136 
    116   return res; 
    117 } 
     137  // Skip leading zeros 
     138  while (*s && *s == '0') 
     139    s++; 
    118140 
    119 S32 atos32(const char *s) { 
    120   U32 len, i = 1, start = 0; 
    121   S32 res = 0; 
    122   bool negative = FALSE; 
     141  for (; *s; s++) { 
     142    // Return 0 on invalid characters. 
     143    if (*s < '0' || *s > '9') 
     144      return FALSE; 
    123145 
    124   len = strlen(s); 
    125   if (len == 0 || len > 11) { 
    126     return 0; 
     146    *result = (10 * *result) + (*s - '0'); 
     147 
     148    // Naive overflow check. We could do better in pure asm by 
     149    // checking the ALU flags. 
     150    if (*result < prev) 
     151      return FALSE; 
     152 
     153    prev = *result; 
    127154  } 
    128155 
    129   if (s[0] == '-') { 
    130     negative = TRUE; 
    131     start++; 
    132   } 
     156  if (negative) 
     157    *result = -(*result); 
    133158 
    134   for (; len>start; len--) { 
    135     char c = s[len-1]; 
    136  
    137     /* If one character is invalid, fail by returning 0. */ 
    138     if (c < '0' || c > '9') { 
    139       return 0; 
    140     } 
    141  
    142     res += (c - '0') * i; 
    143     i *= 10; 
    144   } 
    145  
    146   return negative ? - res : res; 
     159  return TRUE; 
    147160} 
  • nxos/base/util.h

    r556 r558  
    101101 * 
    102102 * @param s The string to convert. 
    103  * @return The converted integer, or 0 by default. 
     103 * @param result A pointer to the integer that will contain the parsed 
     104 * result, if the conversion was successful. 
     105 * @return TRUE with *result set correctly if the conversion was 
     106 * successful, FALSE if the conversion failed. 
     107 * 
     108 * @note If the conversion fails, the value of @a *result will still 
     109 * be clobbered, but won't contain the true value. 
    104110 */ 
    105 U32 atou32(const char *s); 
     111bool atou32(const char *s, U32* result); 
    106112 
    107113/** Convert a string to the signed integer it represents, if possible. 
    108114 * 
    109115 * @param s The string to convert. 
    110  * @return The converted integer, or 0 by default. 
     116 * @param result A pointer to the integer that will contain the parsed 
     117 * result, if the conversion was successful. 
     118 * @return TRUE with *result set correctly if the conversion was 
     119 * successful, FALSE if the conversion failed. 
     120 * 
     121 * @note If the conversion fails, the value of @a *result will still 
     122 * be clobbered, but won't contain the true value. 
    111123 */ 
    112 S32 atos32(const char *s); 
     124bool atos32(const char *s, S32* result); 
    113125 
    114126/*@}*/ 
  • nxos/systems/tests/main.c

    r556 r558  
    2323  //tests_usb_hardcore(); 
    2424  //tests_radar(); 
     25  tests_util(); 
    2526} 
  • nxos/systems/tests/tests.c

    r556 r558  
    1111/* TODO: evil, decide if necessary. */ 
    1212#include "base/drivers/_avr.h" 
    13 //#include "base/drivers/twi.h" 
    14 //#include "base/drivers/lcd.h" 
    1513#include "base/drivers/sound.h" 
    1614#include "base/drivers/sensors.h" 
     
    4543 
    4644void tests_util(void) { 
    47   hello(); 
     45  U32 u = 0; 
     46  S32 s = 0; 
     47  hello(); 
     48 
     49  /* 
     50   * streq() tests. 
     51   */ 
    4852 
    4953  /* Simple equality. */ 
     
    6973  NX_ASSERT(streq("", "")); 
    7074 
     75  /* 
     76   * streqn() tests. 
     77   */ 
    7178 
    7279  /* Simple equality. */ 
     
    97104  /* Prefix equality of unequal strings */ 
    98105  NX_ASSERT(streqn("feh", "foo", 1)); 
     106 
     107  /* 
     108   * atou32() tests. 
     109   */ 
     110 
     111  NX_ASSERT(atou32("42", &u) && u == 42); 
     112  NX_ASSERT(atou32("0", &u) && u == 0); 
     113  NX_ASSERT(atou32("00000000000000", &u) && u == 0); 
     114  NX_ASSERT(atou32("0042", &u) && u == 42); 
     115  NX_ASSERT(!atou32("arthur", &u)); 
     116  /* 4294967295 is 2^32-1, aka U32_MAX */ 
     117  NX_ASSERT(atou32("4294967295", &u) && u == 4294967295U); 
     118  NX_ASSERT(!atou32("4294967296", &u)); 
     119  /* TODO: massive overflows don't get caught because of our naive 
     120   * checking logic. Need to fix. 
     121   */ 
     122  NX_ASSERT(atou32("9999999999", &u)); 
     123 
     124  /* 
     125   * atos32() tests. 
     126   */ 
     127 
     128  NX_ASSERT(atos32("42", &s) && s == 42); 
     129  NX_ASSERT(atos32("-42", &s) && s == -42); 
     130  NX_ASSERT(atos32("0", &s) && s == 0); 
     131  NX_ASSERT(atos32("-0", &s) && s == 0); 
     132  NX_ASSERT(atos32("00000000000000", &s) && s == 0); 
     133  NX_ASSERT(atos32("0042", &s) && s == 42); 
     134  NX_ASSERT(atos32("-0042", &s) && s == -42); 
     135  NX_ASSERT(!atos32("arthur", &s)); 
     136  /* 2147483647 is 2^32-1, aka S32_MAX */ 
     137  NX_ASSERT(atos32("2147483647", &s) && s == 2147483647); 
     138  NX_ASSERT(atos32("-2147483647", &s) && s == -2147483647); 
     139  NX_ASSERT(!atos32("2147483648", &s)); 
     140  /* TODO: We should be able to represent -2^31, but our conversion logic 
     141   * considers it an error. Fix it if one day we actually need -2^31. 
     142   */ 
     143  NX_ASSERT(!atos32("-2147483648", &s)); 
     144  /* TODO: massive overflows and underflows don't get caught because 
     145   * of our naive checking logic. Need to fix. 
     146   */ 
     147  NX_ASSERT(atos32("9999999999", &s)); 
     148  NX_ASSERT(atos32("-9999999999", &s)); 
    99149 
    100150  goodbye();