Home | History | Annotate | Line # | Download | only in examples
raii.cpp revision 1.1
      1 // Copyright 2012 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 // * Redistributions of source code must retain the above copyright
      9 //   notice, this list of conditions and the following disclaimer.
     10 // * Redistributions in binary form must reproduce the above copyright
     11 //   notice, this list of conditions and the following disclaimer in the
     12 //   documentation and/or other materials provided with the distribution.
     13 // * Neither the name of Google Inc. nor the names of its contributors
     14 //   may be used to endorse or promote products derived from this software
     15 //   without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 /// \file examples/raii.cpp
     30 /// Demonstrates how RAII helps in keeping the Lua state consistent.
     31 ///
     32 /// One of the major complains that is raised against the Lua C API is that it
     33 /// is very hard to ensure it remains consistent during the execution of the
     34 /// program.  In the case of native C code, there exist many tools that help the
     35 /// developer catch memory leaks, access to uninitialized variables, etc.
     36 /// However, when using the Lua C API, none of these tools can validate that,
     37 /// for example, the Lua stack remains balanced across calls.
     38 ///
     39 /// Enter RAII.  The RAII pattern, intensively applied by Lutok, helps the
     40 /// developer in maintaining the Lua state consistent at all times in a
     41 /// transparent manner.  This example program attempts to illustrate this.
     42 
     43 #include <cassert>
     44 #include <cstdlib>
     45 #include <iostream>
     46 #include <string>
     47 
     48 #include <lutok/operations.hpp>
     49 #include <lutok/stack_cleaner.hpp>
     50 #include <lutok/state.ipp>
     51 
     52 
     53 /// Prints the string-typed field of a table.
     54 ///
     55 /// If the field contains a string, this function prints its value.  If the
     56 /// field contains any other type, this prints an error message.
     57 ///
     58 /// \pre The top of the Lua stack in 'state' references a table.
     59 ///
     60 /// \param state The Lua state.
     61 /// \param field The name of the string-typed field.
     62 static void
     63 print_table_field(lutok::state& state, const std::string& field)
     64 {
     65     assert(state.is_table());
     66 
     67     // Bring in some RAII magic: the stack_cleaner object captures the current
     68     // height of the Lua stack at this point.  Whenever the object goes out of
     69     // scope, it will pop as many entries from the stack as necessary to restore
     70     // the stack to its previous level.
     71     //
     72     // This ensures that, no matter how we exit the function, we do not leak
     73     // objects in the stack.
     74     lutok::stack_cleaner cleaner(state);
     75 
     76     // Stack contents: -1: table.
     77     state.push_string(field);
     78     // Stack contents: -2: table, -1: field name.
     79     state.get_table();
     80     // Stack contents: -2: table, -1: field value.
     81 
     82     if (!state.is_string()) {
     83         std::cout << "The field " << field << " does not contain a string\n";
     84         // Stack contents: -2: table, -1: field value.
     85         //
     86         // This is different than when we started!  We should pop our extra
     87         // value from the stack at this point.  However, it is extremely common
     88         // for software to have bugs (in this case, leaks) in error paths,
     89         // mostly because such code paths are rarely exercised.
     90         //
     91         // By using the stack_cleaner object, we can be confident that the Lua
     92         // stack will be cleared for us at this point, no matter what happened
     93         // earlier on the stack nor how we exit the function.
     94         return;
     95     }
     96 
     97     std::cout << "String in field " << field << ": " << state.to_string()
     98               << '\n';
     99     // A well-behaved program explicitly pops anything extra from the stack to
    100     // return it to its original state.  Mostly for clarity.
    101     state.pop(1);
    102 
    103     // Stack contents: -1: table.  Same as when we started.
    104 }
    105 
    106 
    107 /// Program's entry point.
    108 ///
    109 /// \return A system exit code.
    110 int
    111 main(void)
    112 {
    113     lutok::state state;
    114     state.open_base();
    115 
    116     lutok::do_string(state, "example = {foo='hello', bar=123, baz='bye'}");
    117 
    118     state.get_global("example");
    119     print_table_field(state, "foo");
    120     print_table_field(state, "bar");
    121     print_table_field(state, "baz");
    122     state.pop(1);
    123 
    124     return EXIT_SUCCESS;
    125 }
    126