STL for microprocessors

Posted by Nick Gammon on Wed 18 May 2011 04:11 AM — 5 posts, 64,006 views.

Australia Forum Administrator #0
Andy Brown's port of the STL


I found a port of the STL for AVR microprocessors here:

http://andybrown.me.uk/ws/2011/01/15/the-standard-template-library-stl-for-avr-with-c-streams/

This is extremely handy if you want to use vectors, maps etc. in the fairly minimalist environment of programming Arduino or similar chips.

Testing indicates that, depending on what features you use, you may consume around another 1000 bytes of program memory (for a simple vector). Using a map adds 2400 bytes or so. Using both adds 2800 bytes (they would share some code).

So that isn't too bad, considering the Atmega328 has 32 Kb of program memory.

In case his site ever goes down I have a copy here:

http://www.gammon.com.au/Arduino/avr-stl-1.1.zip




Maniacbug's port of the STL


I have found some issues with Andy Brown's port in recent versions of the Arduino IDE. An alternative can be found here:

https://github.com/maniacbug/StandardCplusplus

In the case of Maniacbug's port, just download the file from GitHub, remove the word "-master" from the end of it, and install into your libraries directory. No fiddling around with the IDE download is required.

For this port, just include this line at the start of any sketch requiring the STL:


#include <StandardCplusplus.h>


Installation instructions for Andy Brown's port


Quote:

If you want to use the STL from within the popular Arduino IDE then all you need to do is copy all the files in the avr-stl\include directory into the hardware\tools\avr\avr\include subdirectory of the Arduino installation. For example, on my system I would copy all the header files into here: C:\Program Files (x86)\arduino-0021\hardware\tools\avr\avr\include.



Tip:
For Ubuntu, I found the directory structure slightly different, and copied the files from the avr-stl/include directory into:

~/arduino-1.0.6/hardware/tools/avr/lib/avr/include/


Of course, the "~/arduino-1.0.6" part would be wherever you installed your copy of the Arduino IDE.


Configuration (to affect how memory is allocated) is here:

Quote:

All configuration options may be found in avr_config.h.


You need to include <iterator> or you will get compile errors. You also need <new.cpp> in one file of your project to get the 'new' and 'delete' operators.

[EDIT] For Arduino 1.0 onwards you don't need <new.cpp> but you need <pnew.cpp> instead to get "placement new".

Example minimal code



#include <iterator>
#include <vector>
#include <map>
#include <new.cpp>

void setup ()
{
  std::vector<byte> v;
  
  v.push_back (1);
  
  std::map<byte, byte> m;
  
  m [1] = 2;
}  // end of setup

void loop () {}


Credits


The code was released under the "Attribution-ShareAlike 3.0 Unported" license:

http://creativecommons.org/licenses/by-sa/3.0/


All credit and thanks to Andy Brown for making this port available.


More elaborate example



// stl test

#include <iterator>
#include <string>
#include <vector>
#include <serstream>
#include <pnew.cpp>  // placement new implementation

using namespace std;

ohserialstream serial(Serial);
    
void showv (const string s, const vector<string> & v)
  {
  serial << s << endl;
  copy(v.begin(), v.end(), ostream_iterator<string>(serial, " "));
  serial << endl << endl;
  } // end of showv
  
// case-independent (ci) string less_than
// returns true if s1 < s2
struct ci_less : binary_function<string, string, bool>
  {

  // case-independent (ci) compare_less binary function
  struct nocase_compare : public binary_function<unsigned char,unsigned char,bool> 
    {
    bool operator() (const unsigned char& c1, const unsigned char& c2) const 
      { return tolower (c1) < tolower (c2); }
    };

  bool operator() (const string & s1, const string & s2) const
    {
  
    return lexicographical_compare 
          (s1.begin (), s1.end (),   // source range
           s2.begin (), s2.end (),   // dest range
                nocase_compare ());  // comparison
    }
  }; // end of ci_less


void setup() {
  
  Serial.begin (115200);
  
   // vector of strings
  vector<string> v;

  // make a back insert iterator to safely add to the back of the vector
  back_insert_iterator<vector<string> > i(v);
  
// Insert items into the vector. 
// Strictly speaking, the "++" is not needed, as the
// assignment to the iterator is what advances it.

  *i++ = "The";
  *i++ = "quick";
  *i++ = "brown";
  *i++ = "fox";
  *i++ = "jumped";
  *i++ = "over";
  *i++ = "the";
  *i++ = "lazy";
  *i++ = "dog";

  showv ("initial vector...", v);

  // sort ascending
  sort (v.begin (), v.end ());
  showv ("after sort (ascending)...", v);

  // sort descending by using greater function to compare less
  sort (v.begin (), v.end (), greater<string> ());
  showv ("after sort (descending)...", v);

  // sort case-independent by using our own compare-less
  sort (v.begin (), v.end (), ci_less ());
  showv ("after case-independent sort (ascending)...", v);

  // reverse that by doing a "not" on the result
  sort (v.begin (), v.end (), not2 (ci_less ()));
  showv ("after case-independent sort (descending)...", v);
 
  // shuffle the words
  random_shuffle (v.begin (), v.end ());
  showv ("after shuffle...", v);

  // rotate them
  rotate (v.begin (), v.begin () + 1, v.end ());
  showv ("after rotate 1 to the left...", v);

  // reverse their order
  reverse (v.begin (), v.end ());
  showv ("after reverse...", v);

  // add "(" to the beginning of each one
  transform (v.begin (), v.end (),
             v.begin (),
             bind1st (plus<string> (), "("));

  // add ")" to the end of each one
  transform (v.begin (), v.end (),
             v.begin (),
             bind2nd (plus<string> (), ")"));
  showv ("after transforms...", v);

} // end of setup

void loop() { }


Bug in string class


See Andy's notes about modifying line 1107 of the "string" header file to read like this:


  = (typename basic_string<_CharT,_Traits,_Alloc>::size_type) -1;


Problems with IDE 1.6.0


In addition to the above change, to compile under IDE 1.6.0 you need to add "this->" in two places as described below:

In file "string" at line 173:


    { this->_M_deallocate(_Base::_M_start, _Base::_M_end_of_storage - _Base::_M_start); }


In file "stl_vector.h" at line 117:


  ~_Vector_base() { this->_M_deallocate(_Base::_M_start, _Base::_M_end_of_storage - _Base::_M_start); }
Amended on Tue 11 Aug 2015 11:02 PM by Nick Gammon
#1
Sorry to resurrect a dead thread, but I'm hoping someone can point me in a good direction. I'm a C++ noob (I'm a Java developer though, so its not completely unfamiliar), and have just discovered this avr-stl library - what a great resource!

I'm using Eclipse CDT (Juno version) with the AVR-Eclipse plugin, and am trying to hook the avr-stl files into my Eclipse project.

I went to the project's 'Properties : C/C++ General : Paths and Symbols : Includes' section, and added the avr-stl/include directory to the GNU C++ language. The IDE now recognizes the std::vector reference (I #included <vector> in my cpp file), and provides appropriate popup hints, etc in the editor.

When I compile my project, however, I get a whole slew of error messages about code in the avr-stl source files - all kinds of stuff about 'ISO C++ forbids' this or that, things not declared in the current scope, expecting ';' before '*' token, etc, etc - a big mess. FWIW, I can see the ' -I/Users/jim/Documents/avrlibs/avr-stl/include' in the call to the AVR C++ Compiler (and given all the errors, its clearly finding the avr-stl code :-)

I'm using the AVR-GCC toolchain.

Any thoughts on what I'm doing wrong on this? I'm really excited about having found this set of APIs, but cannot actually use them. :-(

Thanks!
#2
Incidentally, I just tried using this under Atmel Studio 6, and got a very similar stream of errors from within the avr-stl source files. Its not an exact line-by-line match, but there are many, many identical messages in the same basic order. Anyway, it seems that perhaps its not just a config issue with my Eclipse CDT setup. (Perhaps its a config issue in my config of both Eclipse and AS6... :-)
#3
Aak... I'm not just a noob, I'm a non-RTFM'ing noob... I found the answer in the comments on Andy's site (and you also had it in your sample code in this thread - talk about blind!) I hadn't included <iterator> or <pnew.cpp>. The order seems to be important, and FWIW, the order seems to need to be: (again, as you had it...)

#include <iterator>
#include <vector>
#include <pnew.cpp>

Its compiling like a champ now. Next step is to figure out how to actually use the libraries.

Sorry to have dug this back up, but maybe some other non-RTFM'ing noob will see this and skip some frustration some day. <:-)

Thanks Again!
Australia Forum Administrator #4
Yep, normal STL doesn't require this, but the way all the includes work, you need that for this port.