Boost logo

Boost :

From: Herve Bronnimann (hbr_at_[hidden])
Date: 2000-10-19 15:00:01


Hi everyone:

Upon designing generic compression filters, I stumbled onto the problem
of retrieving the unsigned numeric type corresponding to a given
integral or character type. The problem is to map a symbol onto an index
into an array, suitably so that indices range in [0,max_index+1).
Thus the concept of a symbol map.

Apparently, char_traits gives a conversion to an integral type, but this
integral might be signed. To convert to the corresponding unsigned
type, using the same or more bits, I wrote the following class template.

It's not clear to me if <boost/integer.hpp> and <boost/type_traits.hpp>
can shorten my code. In particular, neither of them would let me handle
wchar_t. It would be possible however to use them to avoid unnecessary
conversions. In this particular case, I couldn't find how to solve my
problem using only the boost libraries.

As I am a beginner to boost, please bear with me and let me know if my
emails are off-topic for this list. Especially about mailing code which
is not in boost (yet?). Any comments appreciated,

-- 
Hervé
#ifndef SYMBOL_MAP_H
#define SYMBOL_MAP_H
/* Symbol maps transform a symbol into an index in an array and vice
 * versa. Useful for counting frequencies or other encodings without
 * using maps which are less efficient that arrays. They also
 * contain the type and size of the return range for builtin types.
 * You can supply your own symbol_map (if you don't like the default
 * encoding, you are dealing with another alphabet, for colors in
 * images, etc.) */
// For signed types, the index_type should be unsigned to avoid trouble
// We use partial specialization to override the default for those types
// The specializations are at the end of this file for readability
template <class Symbol> struct symbol_traits
{
  static const bool is_unsigned = true;
  typedef Symbol index_type;
  // the following is a safe expression for 2^n - 1, n <= 8*sizeof(long)
  static const unsigned long max_index = index_type(-1);
};
template <class Symbol>
const unsigned long symbol_traits<Symbol>::max_index;
// The symbol map takes advantage of the traits
template <class Symbol, bool is_unsigned>
struct special_symbol_map {};
template <class Symbol>
struct symbol_map
: special_symbol_map< Symbol, symbol_traits<Symbol>::is_unsigned >
{};
// There are two partial specializations. This is because, if unsigned,
// the two operator() have the same signature, having them both in
// symbol_map:: would result in a conflict.
template <class Symbol>
struct special_symbol_map<Symbol,true> {
  typedef Symbol                  symbol_type;
  typedef Symbol                  index_type;
  index_type  operator()(const symbol_type& s) const { return (index_type)s; }
  // shall I use std::static_cast<>?
};
template <class Symbol>
struct special_symbol_map<Symbol,false> {
  typedef Symbol                                     symbol_type;
  typedef typename symbol_traits<Symbol>::index_type index_type;
  index_type  operator()(const symbol_type& s) const { return (index_type)s; }
  symbol_type operator()(const index_type& s)  const { return (symbol_type)s; }
  // shall I use std::static_cast<>?
};
// Specializations for the symbol_traits
#define __declare_index_type(__symbol_type,__signedness,__index_type) \
template <>  \
struct symbol_traits<__symbol_type> \
{ \
  static const bool is_unsigned = __signedness; \
  typedef __index_type index_type; \
  static const unsigned long max_index = index_type(-1); \
}; \
template <>  \
const bool symbol_traits<__symbol_type>::is_unsigned; \
template <>  \
const unsigned long symbol_traits<__symbol_type>::max_index;
// Integral types as per the standard (3.9.1, p. 53)
__declare_index_type(bool,true,bool)
__declare_index_type(char,false,unsigned char)
__declare_index_type(unsigned char,true,unsigned char)
__declare_index_type(signed char,false,unsigned char)
__declare_index_type(short,false,unsigned short)
__declare_index_type(unsigned short,true,unsigned short)
__declare_index_type(int,false,unsigned int)
__declare_index_type(unsigned int,true,unsigned int)
__declare_index_type(long int,false,unsigned long int)
__declare_index_type(unsigned long int,true,unsigned long int)
// this type makes it unfortunately not possible to use
// <boost/integer.hpp> directly
__declare_index_type(wchar_t,false,short)
#endif // SYMBOL_MAP_H

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk