Create a streambuf from const char* WITHOUT boost? - c++

Same question as Create a streambuf from const char* except that I can't use boost.
I have to implement an function that takes a const char * as input parameter, and to do so I have to call an other function that takes a istream as input parameter.
Here is a sample of code very simplified:
#include <iostream>
#include <string>
using namespace std ;
void inner_function_I_cant_change ( istream & input ) // the function I must use
{
string s ; // dummy implementation
input >> s ;
cout << s.size() << " : <" << s << ">" << endl ;
}
struct externbuf : streambuf // my own streambuf using a char*...
{
int size ;
bool done ;
char * buffer ;
externbuf ( const char * buffer , int size ) :
size(size),
done(false),
buffer(const_cast<char*>( buffer )) {} // ...that forces me to an ugly const_cast !
int underflow ()
{
if (this->gptr() == this->egptr())
{
if (done) return std::char_traits<char>::eof() ;
this->setg( buffer,buffer,buffer+size ) ;
done = true ;
}
return char_traits<char>::to_int_type( *this->gptr()) ;
}
};
void API_function_I_must_povide ( const char * data , int size ) // the function I must implement
{
externbuf buf( data,size ) ;
istream input( &buf ) ;
inner_function_I_cant_change( input ) ;
}
int main ()
{
API_function_I_must_povide( "bazinga!",8 ) ;
}
This code I works well but I had to do an ugly const_cast !
I tried using a basic_streambuf<const char, char_traits<const char> > instead of a streambuf but I get many errors that I didn't understand well.
Is there a proper way to do it ?
(and, as I said, I can't use boost)
Thanks !

Thanks Remy, your link to Art Of Code made my day!
So, for those who are interested, here my new code, without memcpy and ugly const_cast:
#include <iostream>
#include <string>
using namespace std ;
void inner_function_I_cant_change ( istream & input )
{
char buffer [1000] ;
input.read( buffer,sizeof buffer ) ;
string s1( buffer,input.gcount()) ;
string s2( "hello \0 world !",15 ) ;
if (s1 == s2)
cout << "success!" ;
}
struct externbuf : public streambuf
{
externbuf ( const char * data , unsigned int len ) : begin(data),crt(data),end(data + len) {}
int_type underflow ()
{
return crt == end ? traits_type::eof() : traits_type::to_int_type( *crt ) ;
}
int_type uflow ()
{
return crt == end ? traits_type::eof() : traits_type::to_int_type( *crt++ ) ;
}
int_type pbackfail ( int_type ch )
{
bool cond = crt == begin || (ch != traits_type::eof() && ch != crt[-1]) ;
return cond ? traits_type::eof() : traits_type::to_int_type( *--crt ) ;
}
streamsize showmanyc ()
{
return end - crt ;
}
const char *begin,*crt,*end ;
};
void API_function_I_must_povide ( const char * data , int size )
{
externbuf buf( data,size ) ;
istream input( &buf ) ;
inner_function_I_cant_change( input ) ;
}
int main ()
{
API_function_I_must_povide( "hello \0 world !",15 ) ;
}
Thanks Pete, your solution is development-less but I'm afraid it induces a memcpy from data to the inner buffer of the std::string. And since my buffer may be very big, I try to avoid them as much as possible.

Related

C++ templates: How to conditionally compile different code based on data type?

Here's a small example that illustrates the essence of my question:
#include <iostream>
using namespace std ;
typedef char achar_t ;
template < class T > class STRING
{
public:
T * memory ;
int size ;
int capacity ;
public:
STRING() {
size = 0 ;
capacity = 128 ;
memory = ( T *) malloc( capacity * sizeof(T) ) ;
}
const STRING& operator=( T * buf) {
if ( typeid(T) == typeid(char) )
strcpy( memory, buf ) ;
else
wcscpy( memory, buf ) ;
return *this ;
}
} ;
void main()
{
STRING<achar_t> a ;
STRING<wchar_t> w ;
a = "a_test" ;
w = L"w_test" ;
cout << " a = " << a.memory << endl ;
cout << " w = " << w.memory << endl ;
}
Can some one please help me compile the above? That is somehow compile either with strcpy() or wcscpy() based on the type of the object i am using.
thank you
Use std::char_traits<CharT>.
You can replace strcpy() and wcscpy() by combining the static methods std::char_traits::length() and std::char_traits::copy(). This will also make your code more generic because std::char_traits has specializations for char16_t and char32_t.
STRING& operator=( T const * buf) {
// TODO: Make sure that buffer size for 'memory' is large enough.
// You propably also want to assign the 'size' member.
auto len = std::char_traits< T >::length( buf );
std::char_traits< T >::copy( memory, buf, len );
return *this ;
}
Side notes:
I changed the type of parameter buf to T const* because it is not legal to assign a string literal to a pointer that points to non-const data. We only need read access to the data pointed to by buf.
I changed the return type to STRING& because that's the way how the assignment operator usually is declared. The method must be non-const so there is no point in restricting the return type to a constant reference.
If you are using C++17, you can use if constexpr also:
if constexpr (std::is_same<char, T>::value)
strcpy( memory, buf );
else
wcscpy( memory, buf );
The branch that fails the condition will not be compiled for the given template instantiation.
You can use template specialization.
template<typename T>
class STRING {
public:
T * memory ;
int size ;
int capacity ;
public:
STRING() {
size = 0 ;
capacity = 128 ;
memory = ( T *) malloc( capacity * sizeof(T) ) ;
}
STRING const & operator=(T * buf);
};
And you define a specialization for the type you want
template<> STRING<achar_t> const & STRING<achar_t>::operator=(achar_t * buf)
{
strcpy(memory, buf );
return *this;
}
template<> STRING<wchar_t> const & STRING<wchar_t>::operator=(wchar_t * buf)
{
wcscpy( memory, buf );
return *this;
}
I didn't test this code but you can find more information here http://en.cppreference.com/w/cpp/language/template_specialization

Function pointer pointed to a member function

I am just learning function pointer and want to test how it works with member functions. The compilation of the following code fails at where it is marked.
# include <iostream>
# include <stdio.h>
using namespace std ;
class TMyClass {
public:
int DoIt ( float a, char b, char c ) {
cout << " TMyClass::DoIt " << endl ;
return a + b + c ;
}
int DoMore ( float a, char b, char c ) {
cout << " TMyClass::DoMore " << endl ;
return a - b + c ;
}
int ( TMyClass::*pt2Member ) ( float, char, char ) ;
int test_function_pointer ( ) {
this->pt2Member = &TMyClass::DoMore ;
int result = ( this -> *pt2Member ) ( 12, 'a', 'b' ) ; // wrong!
// expected unqualified-id before "*" token
return 0 ;
}
} ;
int main () {
TMyClass A ;
A.test_function_pointer () ;
return 0 ;
}
I wonder how to make it work. Thanks!
What a difference a space makes:
int result = ( this ->* pt2Member ) ( 12, 'a', 'b' );
// ^^^
->* is an operator of its own.
See the fixed demo here please.
This line:
int result = ( this -> *pt2Member ) ( 12, 'a', 'b' ) ; // wrong!
should have been:
int result = ( this ->*pt2Member ) ( 12, 'a', 'b' ) ; // wrong!
->* is an operator and you cannot insert spaces inside it as it splits it into two different operators: -> and *. This is similar to <<, >>, --, ++ which also cannot be split by spaces into two different tokens.

Templated operator<< isn't being recognized

I created a class called SkipToChar that's supposed to be able to be used as follows:
std::ostringstream oss;
oss << "Hello," << SkipToChar(7) << "world!" << std::endl;
Which would print "Hello, world!" (notice the space.) Basically it's supposed to skip to the character at the specified index using spaces. But apparently the compiler doesn't recognize the operator<< I created for it. Interestingly, calling operator<< explicitly, even without giving any template parameters (like operator<<(oss, SkipToChar(7)); works fine; it just doesn't work if I actual
Here's my code:
#include <iostream>
#include <sstream>
template <typename _Elem>
struct basic_SkipToChar
{
typename std::basic_string<_Elem>::size_type pos;
basic_SkipToChar(typename std::basic_string<_Elem>::size_type position)
{
pos = position;
}
};
template <typename _Elem>
inline std::basic_ostringstream<_Elem> &operator<<(std::basic_ostringstream<_Elem> &oss, const basic_SkipToChar<_Elem> &skip)
{
typename std::basic_string<_Elem>::size_type length = oss.str().length();
for (typename std::basic_string<_Elem>::size_type i = length; i < skip.pos; i++) {
oss << (_Elem)' ';
}
return oss;
}
typedef basic_SkipToChar<char> SkipToChar;
typedef basic_SkipToChar<wchar_t> WSkipToChar;
int main(int argc, char *argv[])
{
std::ostringstream oss;
/*ERROR*/ oss << "Hello," << SkipToChar(8) << "world!" << std::endl;
std::cout << oss.str();
return 0;
}
It gives me the following error when I try to compile it:
error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'basic_SkipToChar<char>' (or there is no acceptable conversion)
I marked the line the error is on with a comment. What's going wrong here?
oss << "Hello," returns std::basic_ostream<char> (it loses the string part).
So your method doesn't match (expect std::basic_ostringstream but got std::basic_ostream<char>).
As Jarod42 points out, the return type of all of the built-in
operator<< is std::ostream&. This is a basic principle of
how streams operator; except for the actual sink or source, the
stream should be indifferent as to where the data is going to or
coming from.
It's possible to provide manipulators which only work for one
type of stream, or do different things for different types of
streams, by using a dynamic_cast in the manipulator:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
std::ostringstream* d = dynamic_cast<std::ostringstream*>( &dest );
if ( d != nullptr ) {
// ...
}
return dest;
}
In general, however, this is a very bad idea; clients will be
very surprised that outputting to a string results in different
text than outputting to a file.
What you seem to be trying to do is to more or less emulate
a form of tabbing. The best way to do this is to use
a filtering output streambuf, which keeps track of where you are
in the line, and can be inserted between the std::ostream and
the actual sink regardless of the type of stream:
class TabbingOutputStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
int myInLineCount;
public:
TabbingOutputStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myInLineCount( 0 )
{
}
TabbingOutputStreambuf( std::ostream& dest )
: myDest( dest.rdbuf() )
, myOwner( &dest )
, myInLineCount( 0 )
{
myOwner.rdbuf( this );
}
~TabbingOutputStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
int overflow( int ch ) override
{
if ( ch == '\n' ) {
myInLineCount = 0;
} else {
++ myInLineCount;
}
return myDest->sputc( ch );
}
// Special function...
int tabTo( int n )
{
int retval = 0;
while ( retval == 0 && myInLineCount < n ) {
if ( overflow( ' ' ) == EOF ) {
retval = EOF;
}
}
return retval;
}
};
Your manipulator would then be:
std::ostream&
operator<<( std::ostream& dest, SkipToChar const& manip )
{
TabbingOutputStreambuf* sb = dynamic_cast<TabbingOutputStreambuf*>( dest.rdbuf() );
assert( sb != nullptr );
try {
if ( sb->tabTo( manip.pos ) == EOF ) {
dest.setstate( std::badbit );
}
} catch ( ... ) {
dest.setstate( std::badbit );
}
return dest;
}
This is still not ideal, since it will fail with an unprotected
buffer, but you'd only use the manipulator in a context like:
void
generateOutput( std::ostream& dest )
{
TabbingOutputStreambuf tabber( dest );
dest << "Hello, " << SkipToChar( 7 ) << "world!";
// ...
}
And this will work regardless of the type of stream passed to
the function (including custom ostream classes that you don't
even know about).
EDIT:
One last point: don't bother with making things templates until you've got the basic version working. (For what it's worth, your code doesn't work correctly for wchar_t streams anyway. To output a space in them, you need to get the embedded locale, get the ctype facet from it, and use its widen member function.)

Display escape sequences as text only

My program is outputting text which sometimes contains escape sequences such as "\x1B[J" (Clear screen). Is there anyway to suppress the escape sequence such that it doesn't perform its associated action but instead gets displayed via its text representation?
I would even be interested in doing this for \n and \r.
Escape the \ characters by changing each occurence to \\.
Note that these sequences work only, when you enter them in source code. Check the result of the following program:
#include <cstdio>
int main(int argc, char * argv[])
{
char test[3] = { 0x5c, 0x6e, 0x00 }; // \n
char * test2 = "\\n"; // \n
printf("%s\n", test);
printf("%s\n", test2);
printf(test);
printf(test2);
return 0;
}
It's not clear at what level you want to intervene. If you're
writing the output, the simplest solution is just to not insert
the characters to begin with. If you're passing an
std::ostream to some library, and it's inserting the
characters, it's fairly simply to insert a filtering streambuf
into the output stream, and filter them out. Something like the
following should do the trick for the standard escape sequences:
class EscapeSequenceFilter
{
std::streambuf* myDest;
std::ostream* myOwner;
bool myIsInEscapeSequence;
protected:
int overflow( int ch )
{
int retval = ch == EOF ? ch : 0;
if ( myIsInEscapeSequence ) {
if ( isalpha( ch ) ) {
myIsInEscapeSequence = false;
} else if ( ch == 0x1B ) {
myIsInEscapeSequence = true;
} else {
retval = myDest->sputc( ch );
}
return retval;
}
public:
EscapeSequenceFilter( std::streambuf* dest )
: myDest( dest )
, myOwner( NULL )
, myIsInEscapeSequence( false )
{
}
EscapeSequenceFilter( std::ostream& dest )
: myDest( dest.rdbuf() )
, myOwner( &dest )
, myIsInEscapeSequence( false )
{
myOwner->rdbuf( this );
}
~EscapeSequenceFilter()
{
if ( myOwner != NULL ) {
myOwner->rdbuf( myDest );
}
}
};
Just declare an instance of this class with the output stream as
argument before calling the function you want to filter.
This class is easily extended to filter any other characters you
might wish.

String and character mapping question for the guru's out there

Here's a problem thats got me stumped (solution wise):
Given a str S, apply character mappings Cm = {a=(m,o,p),d=(q,u),...} and print out all possible combinations using C or C++.
The string can be any length, and the number of character mappings varies, and there won't be any mappings that map to another map (thus avoiding circular dependencies).
As an example: string abba with mappings a=(e,o), d=(g,h), b=(i) would print:
abba,ebba,obba,abbe,abbo,ebbe,ebbo,obbe,obbo,aiba,aiia,abia,eiba,eiia,......
Definitely possible, not really difficult... but this will generate lots of strings that's for sure.
The first thing to remark is that you know how many strings it's going to generate beforehand, so it's easy to do some sanity check :)
The second: it sounds like a recursive solution would be easy (like many traversal problems).
class CharacterMapper
{
public:
CharacterMapper(): mGenerated(), mMapped()
{
for (int i = -128, max = 128; i != max; ++i)
mMapped[i].push_back(i); // 'a' is mapped to 'a' by default
}
void addMapped(char origin, char target)
{
std::string& m = mMapped[origin];
if (m.find(target) == std::string::npos) m.push_back(target);
} // addMapped
void addMapped(char origin, const std::string& target)
{
for (size_t i = 0, max = target.size(); i != max; ++i) this->addMapped(origin, target[i]);
} // addMapped
void execute(const std::string& original)
{
mGenerated.clear();
this->next(original, 0);
this->sanityCheck(original);
this->print(original);
}
private:
void next(std::string original, size_t index)
{
if (index == original.size())
{
mGenerated.push_back(original);
}
else
{
const std::string& m = mMapped[original[index]];
for (size_t i = 0, max = m.size(); i != max; ++i)
this->next( original.substr(0, index) + m[i] + original.substr(index+1), index+1 );
}
} // next
void sanityCheck(const std::string& original)
{
size_t total = 1;
for (size_t i = 0, max = original.size(); i != max; ++i)
total *= mMapped[original[i]].size();
if (total != mGenerated.size())
std::cout << "Failure: should have found " << total << " words, found " << mGenerated.size() << std::endl;
}
void print(const std::string& original) const
{
typedef std::map<char, std::string>::const_iterator map_iterator;
typedef std::vector<std::string>::const_iterator vector_iterator;
std::cout << "Original: " << original << "\n";
std::cout << "Mapped: {";
for (map_iterator it = mMapped.begin(), end = mMapped.end(); it != end; ++it)
if (it->second.size() > 1) std::cout << "'" << it->first << "': '" << it->second.substr(1) << "'";
std::cout << "}\n";
std::cout << "Generated:\n";
for (vector_iterator it = mGenerated.begin(), end = mGenerated.end(); it != end; ++it)
std::cout << " " << *it << "\n";
}
std::vector<std::string> mGenerated;
std::map<char, std::string> mMapped;
}; // class CharacterMapper
int main(int argc, char* argv[])
{
CharacterMapper mapper;
mapper.addMapped('a', "eo");
mapper.addMapped('d', "gh");
mapper.addMapped('b', "i");
mapper.execute("abba");
}
And here is the output:
Original: abba
Mapped: {'a': 'eo''b': 'i''d': 'gh'}
Generated:
abba
abbe
abbo
abia
abie
abio
aiba
aibe
aibo
aiia
aiie
aiio
ebba
ebbe
ebbo
ebia
ebie
ebio
eiba
eibe
eibo
eiia
eiie
eiio
obba
obbe
obbo
obia
obie
obio
oiba
oibe
oibo
oiia
oiie
oiio
Yeah, rather lengthy, but there's a lot that does not directly participate to the computation (initialization, checks, printing). The core methods is next which implements the recursion.
EDIT: This should be the fastest and simplest possible algo. Some may argue with the style or portability; I think this is perfect for an embedded-type thing and I've spent long enough on it already. I'm leaving the original below.
This uses an array for mapping. The sign bit is used to indicate the end of a mapping cycle, so the array type has to be larger than the mapped type if you want to use the full unsigned range.
Generates 231M strings/sec or ~9.5 cycles/string on a 2.2GHz Core2. Testing conditions and usage as below.
#include <iostream>
using namespace std;
int const alphabet_size = CHAR_MAX+1;
typedef int map_t; // may be char or short, small performance penalty
int const sign_bit = 1<< CHAR_BIT*sizeof(map_t)-1;
typedef map_t cmap[ alphabet_size ];
void CreateMap( char *str, cmap &m ) {
fill( m, m+sizeof(m)/sizeof(*m), 0 );
char *str_end = strchr( str, 0 ) + 1;
str_end[-1] = ' '; // space-terminated strings
char prev = ' ';
for ( char *pen = str; pen != str_end; ++ pen ) {
if ( * pen == ' ' ) {
m[ prev ] |= sign_bit;
prev = 0;
}
m[ * pen ] = * pen;
if ( prev != ' ' ) swap( m[prev], m[ *pen ] );
prev = *pen;
}
for ( int mx = 0; mx != sizeof(m)/sizeof(*m); ++ mx ) {
if ( m[mx] == 0 ) m[mx] = mx | sign_bit;
}
}
bool NextMapping( char *s, char *s_end, cmap &m ) {
for ( char *pen = s; pen != s_end; ++ pen ) {
map_t oldc = *pen, newc = m[ oldc ];
* pen = newc & sign_bit-1;
if ( newc >= 0 ) return true;
}
return false;
}
int main( int argc, char **argv ) {
uint64_t cnt = 0;
cmap m;
CreateMap( argv[1], m );
char *s = argv[2], *s_end = strchr( s, 0 );
do {
++ cnt;
} while ( NextMapping( s, s_end, m ) );
cerr << cnt;
return 0;
}
ORIGINAL:
Not as short or robust as I'd like, but here's something.
Requires that the input string always contain the alphabetically first letter in each replacement set
Execute a la maptool 'aeo dgh bi' abbd
Output is in reverse-lexicographical order
Performance of about 22 cycles/string (100M strings/sec at 2.2 GHz Core2)
BUT my platform is trying to be clever with strings, slowing it down
If I change it to use char* strings instead, it runs at 142M strings/sec (~15.5 cycles/string)
Should be possible to go faster using a char[256] mapping table and another char[256] specifying which chars end a cycle.
The map data structure is an array of nodes linked into circular lists.
#include <iostream>
#include <algorithm>
using namespace std;
enum { alphabet_size = UCHAR_MAX+1 };
struct MapNode {
MapNode *next;
char c;
bool last;
MapNode() : next( this ), c(0), last(false) {}
};
void CreateMap( string s, MapNode (&m)[ alphabet_size ] ) {
MapNode *mprev = 0;
replace( s.begin(), s.end(), ' ', '\0' );
char *str = const_cast<char*>(s.c_str()), *str_end = str + s.size() + 1;
for ( char *pen = str; pen != str_end; ++ pen ) {
if ( mprev == 0 ) sort( pen, pen + strlen( pen ) );
if ( * pen == 0 ) {
if ( mprev ) mprev->last = true;
mprev = 0;
continue;
}
MapNode &mnode = m[ * pen ];
if ( mprev ) swap( mprev->next, mnode.next ); // link node in
mnode.c = * pen; // tell it what char it is
mprev = &mnode;
}
// make it easier to tell that a node isn't in any map
for ( MapNode *mptr = m; mptr != m + alphabet_size; ++ mptr ) {
if ( mptr->next == mptr ) mptr->next = 0;
}
}
bool NextMapping( string &s, MapNode (&m)[ alphabet_size ] ) {
for ( string::iterator it = s.begin(); it != s.end(); ++ it ) {
MapNode &mnode = m[ * it ];
if ( mnode.next ) {
* it = mnode.next->c;
if ( ! mnode.last ) return true;
}
}
return false;
}
int main( int argc, char **argv ) {
MapNode m[ alphabet_size ];
CreateMap( argv[1], m );
string s = argv[2];
do {
cerr << s << endl;
} while ( NextMapping( s, m ) );
return 0;
}
The way I would go about this is to create an array of indexes the same length as the string, all initialized at zero. We then treat this array of indexes as a counter to enumerate all the possible mappings of our source string. A 0 index maps that position in the string to the first mapping for that character, a 1 to the second, etc. We can step through them in order by just incrementing the last index in the array, carrying over to the next position when we reach the maximum number of mappings for that position.
To use your example, we have the mappings
'a' => 'e', 'o'
'b' => 'i'
With the input string "abba", we need a four element array for our indexes:
[0,0,0,0] => "abba"
[0,0,0,1] => "abbe"
[0,0,0,2] => "abbo"
[0,0,1,0] => "abia"
[0,0,1,1] => "abie"
[0,0,1,2] => "abio"
[0,1,0,0] => "aiba"
[0,1,0,1] => "aibe"
[0,1,0,2] => "aibo"
[0,1,1,0] => "aiia"
[0,1,1,1] => "aiie"
[0,1,1,2] => "aiio"
[1,0,0,0] => "ebba"
[1,0,0,1] => "ebbe"
[1,0,0,2] => "ebbo"
[1,0,1,0] => "ebia"
[1,0,1,1] => "ebie"
[1,0,1,2] => "ebio"
[1,1,0,0] => "eiba"
[1,1,0,1] => "eibe"
[1,1,0,2] => "eibo"
[1,1,1,0] => "eiia"
[1,1,1,1] => "eiie"
[1,1,1,2] => "eiio"
[2,0,0,0] => "obba"
[2,0,0,1] => "obbe"
[2,0,0,2] => "obbo"
[2,0,1,0] => "obia"
[2,0,1,1] => "obie"
[2,0,1,2] => "obio"
[2,1,0,0] => "oiba"
[2,1,0,1] => "oibe"
[2,1,0,2] => "oibo"
[2,1,1,0] => "oiia"
[2,1,1,1] => "oiie"
[2,1,1,2] => "oiio"
Before we start generating these strings, we're going to need somewhere to store them, which in C, means that we're
going to have to allocate memory. Fortunately, we know the length of these strings already, and we can figure out
the number of strings we're going to generate - it's just the product of the number of mappings for each position.
While you can return them in an array, I prefer to use a
callback to return them as I find them.
#include <string.h>
#include <stdlib.h>
int each_combination(
char const * source,
char const * mappings[256],
int (*callback)(char const *, void *),
void * thunk
) {
if (mappings == NULL || source == NULL || callback == NULL )
{
return -1;
}
else
{
size_t i;
int rv;
size_t num_mappings[256] = {0};
size_t const source_len = strlen(source);
size_t * const counter = calloc( source_len, sizeof(size_t) );
char * const scratch = strdup( source );
if ( scratch == NULL || counter == NULL )
{
rv = -1;
goto done;
}
/* cache the number of mappings for each char */
for (i = 0; i < 256; i++)
num_mappings[i] = 1 + (mappings[i] ? strlen(mappings[i]) : 0);
/* pass each combination to the callback */
do {
rv = callback(scratch, thunk);
if (rv != 0) goto done;
/* increment the counter */
for (i = 0; i < source_len; i++)
{
counter[i]++;
if (counter[i] == num_mappings[(unsigned char) source[i]])
{
/* carry to the next position */
counter[i] = 0;
scratch[i] = source[i];
continue;
}
/* use the next mapping for this character */
scratch[i] = mappings[(unsigned char) source[i]][counter[i]-1];
break;
}
} while(i < source_len);
done:
if (scratch) free(scratch);
if (counter) free(counter);
return rv;
}
}
#include <stdio.h>
int print_each( char const * s, void * name)
{
printf("%s:%s\n", (char const *) name, s);
return 0;
}
int main(int argc, char ** argv)
{
char const * mappings[256] = { NULL };
mappings[(unsigned char) 'a'] = "eo";
mappings[(unsigned char) 'b'] = "i";
each_combination( "abba", mappings, print_each, (void *) "abba");
each_combination( "baobab", mappings, print_each, (void *) "baobab");
return 0;
}
You essentially want to do a depth-first search (DFS) or any other traversal down a directed acyclic word graph (DAWG). I will post some code shortly.
There is a link to the snippets archive which does that, here, Permute2.c. There is another variant of the string permutation (I guess you could then filter out those that are not in the map!) See here on the 'snippets' archive...
Hope this helps,
Best regards,
Tom.
simple, recursive permute, with using char map[256]
char *map [256];
/* permute the ith char in s */
perm (char *s, int i)
{
if (!s) return;
/* terminating condition */
if (s[i] == '\0') {
/* add "s" to a string array if we want to store the permutations */
printf("%s\n", s);
return;
}
char c = s[i];
char *m = map [c];
// printf ("permuting at [%c]: %s\n", c, m);
int j=0;
/* do for the first char, then use map chars */
do {
perm (s, i+1);
s[i] = m[j];
} while (m[j++] != '\0');
/* restore original char here, used for mapping */
s[i] = c;
return;
}
int main ()
{
/* map table initialization */
map['a'] = "eo\0";
map['b'] = "i\0";
map['d'] = "gh\0";
/* need modifyable sp, as we change chars in position, sp="abba" will not work! */
char *sp = malloc (10);
strncpy (sp, "abba\0", 5);
perm (sp, 0);
return 0;
}