<commit_before>
/*
  Copyright 1995 The University of Rhode Island and The Massachusetts
  Institute of Technology

  Portions of this software were developed by the Graduate School of
  Oceanography (GSO) at the University of Rhode Island (URI) in collaboration
  with The Massachusetts Institute of Technology (MIT).

  Access and use of this software shall impose the following obligations and
  understandings on the user. The user is granted the right, without any fee
  or cost, to use, copy, modify, alter, enhance and distribute this software,
  and any derivative works thereof, and its supporting documentation for any
  purpose whatsoever, provided that this entire notice appears in all copies
  of the software, derivative works and supporting documentation.  Further,
  the user agrees to credit URI/MIT in any publications that result from the
  use of this software or in any product that includes this software. The
  names URI, MIT and/or GSO, however, may not be used in any advertising or
  publicity to endorse or promote any products or commercial entity unless
  specific written permission is obtained from URI/MIT. The user also
  understands that URI/MIT is not obligated to provide the user with any
  support, consulting, training or assistance of any kind with regard to the
  use, operation and performance of this software nor to provide the user
  with any updates, revisions, new versions or "bug fixes".

  THIS SOFTWARE IS PROVIDED BY URI/MIT "AS IS" AND ANY EXPRESS OR IMPLIED
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  EVENT SHALL URI/MIT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS
  ACTION, ARISING OUT OF OR IN CONNECTION WITH THE ACCESS, USE OR PERFORMANCE
  OF THIS SOFTWARE.
*/

// Implementation for Str.
//
// jhrg 9/7/94

// $Log: Str.cc,v $
// Revision 1.14  1995/07/09 21:29:04  jimg
// Added copyright notice.
//
// Revision 1.13  1995/05/10  15:34:05  jimg
// Failed to change `config.h' to `config_dap.h' in these files.
//
// Revision 1.12  1995/05/10  13:45:30  jimg
// Changed the name of the configuration header file from `config.h' to
// `config_dap.h' so that other libraries could have header files which were
// installed in the DODS include directory without overwriting this one. Each
// config header should follow the convention config_<name>.h.
//
// Revision 1.11  1995/03/16  17:26:41  jimg
// Moved include of config_dap.h to top of includes.
// Added TRACE_NEW switched dbnew debugging includes.
//
// Revision 1.10  1995/03/04  14:34:50  jimg
// Major modifications to the transmission and representation of values:
// 	Added card() virtual function which is true for classes that
// 	contain cardinal types (byte, int float, string).
// 	Changed the representation of Str from the C rep to a C++
// 	class represenation.
// 	Chnaged read_val and store_val so that they take and return
// 	types that are stored by the object (e.g., inthe case of Str
// 	an URL, read_val returns a C++ String object).
// 	Modified Array representations so that arrays of card()
// 	objects are just that - no more storing strings, ... as
// 	C would store them.
// 	Arrays of non cardinal types are arrays of the DODS objects (e.g.,
// 	an array of a structure is represented as an array of Structure
// 	objects).
//
// Revision 1.9  1995/02/10  02:22:49  jimg
// Added DBMALLOC includes and switch to code which uses malloc/free.
// Private and protected symbols now start with `_'.
// Added new accessors for name and type fields of BaseType; the old ones
// will be removed in a future release.
// Added the store_val() mfunc. It stores the given value in the object's
// internal buffer.
// Made both List and Str handle their values via pointers to memory.
// Fixed read_val().
// Made serialize/deserialize handle all malloc/free calls (even in those
// cases where xdr initiates the allocation).
// Fixed print_val().
//
// Revision 1.8  1995/01/19  20:05:19  jimg
// ptr_duplicate() mfunc is now abstract virtual.
// Array, ... Grid duplicate mfuncs were modified to take pointers, not
// referenves.
//
// Revision 1.7  1995/01/11  15:54:33  jimg
// Added modifications necessary for BaseType's static XDR pointers. This
// was mostly a name change from xdrin/out to _xdrin/out.
// Removed the two FILE pointers from ctors, since those are now set with
// functions which are friends of BaseType.
//
// Revision 1.6  1994/12/22  04:32:23  reza
// Changed the default type to String (from Str) to match DDS parser.
//
// Revision 1.5  1994/12/14  19:18:00  jimg
// Added mfunc len(). Replaced size() with a mfunc that returns the size of
// a pointer to a string (this simplifies Structure, ...).
//
// Revision 1.4  1994/12/14  18:04:33  jimg
// Changed definition of size() so that it returns the number of bytes in
// the string.
//
// Revision 1.3  1994/11/29  20:16:32  jimg
// Added mfunc for data transmission.
// Uses special xdr function for serialization and xdr_coder.
// Removed `type' parameter from ctor.
// Added FILE *in and *out to ctor parameter list.
//
// Revision 1.2  1994/09/23  14:36:12  jimg
// Fixed errors in comments.
//
// Revision 1.1  1994/09/15  21:08:48  jimg
// Added many classes to the BaseType hierarchy - the complete set of types
// described in the DODS API design documet is now represented.
// The parser can parse DDS files.
// Fixed many small problems with BaseType.
// Added CtorType.
//
// Revision 1.1  1994/09/09  15:38:45  jimg
// Child class of BaseType -- used in the future to hold specific serialization
// information for integers. Should this be a class that uses BaseType?
//

#ifdef __GNUG__
#pragma implementation
#endif

#include "config_dap.h"

#include <assert.h>
#include <string.h>

#include "Str.h"
#include "util.h"

#ifdef TRACE_NEW
#include "trace_new.h"
#endif

Str::Str(const String &n)
    : BaseType(n, "String", (xdrproc_t)xdr_str_array), _buf("")
{
}

// Return: the number of bytes needed to store the string's value or 0 if no
// storage for the string has been allocated.

unsigned int
Str::len()			// deprecated
{
    return length();
}

unsigned int
Str::length()
{
    return _buf.length();
}

bool
Str::card()
{
    return true;
}

unsigned int
Str::size()			// deprecated
{
    return width();
}

// return the number of bytes that the value of a Str object occupies when
// that value is accessed using read_val().

unsigned int
Str::width()
{
    return sizeof(String);
}

// serialize and deserialize manage memory using malloc and free since, in
// some cases, they must let the xdr library (bundled with the CPU) do the
// allocation and that library will always use malloc/free.

bool
Str::serialize(bool flush)
{
    String *tmp = &_buf;	// kluge for xdr_str

    bool stat = (bool)xdr_str(_xdrout, &tmp);
    if (stat && flush)
	stat = expunge();

    return stat;
}

// deserialize the double on stdin and put the result in BUF.

bool
Str::deserialize(bool reuse)
{
    String *tmp = &_buf;

    return (bool)xdr_str(_xdrin, &tmp);
}

// FIXME old comments
// Copy information in the object's internal buffers into the memory pointed
// to by VAL. If *VAL is null, then allocate memory for the value (a string
// in this case).
//
// NB: return the size of the thing val points to (sizeof val), not the
// length of the string. Thus if there is an array of of strings (i.e., (char
// *)s), then the return value of this mfunc can be used to advance to the
// next char * in that array. This weirdness is needed because C programs
// which will need to interface to libraries built using this toolkit will
// not know about g++ Strings and will need to use the C representation for
// strings, but here in the toolkit I use the String class to cut down on
// memory management problems.

unsigned int
Str::read_val(void **val)
{
    assert(val);

    if (!*val)
	(String *)*val = new String(_buf);
    else
	*(String *)*val = _buf;

    return sizeof(String);
}

// Copy data in VAL to _BUF.
//
// Returns the number of bytes needed for _BUF (which is a pointer in this
// case).

unsigned int
Str::store_val(void *val, bool reuse)
{
    assert(val);

    _buf = *(String *)val;

    return sizeof(String);
}

void
Str::print_val(ostream &os, String space, bool print_decl_p)
{
    if (print_decl_p) {
	print_decl(os, space, false);
	os << " = " << _buf << ";" << endl;
    }
    else
	os << _buf;
}
<commit_msg>Now uses newer function names. Uses the new xdr_str() function in util.cc<commit_after>
/*
  Copyright 1995 The University of Rhode Island and The Massachusetts
  Institute of Technology

  Portions of this software were developed by the Graduate School of
  Oceanography (GSO) at the University of Rhode Island (URI) in collaboration
  with The Massachusetts Institute of Technology (MIT).

  Access and use of this software shall impose the following obligations and
  understandings on the user. The user is granted the right, without any fee
  or cost, to use, copy, modify, alter, enhance and distribute this software,
  and any derivative works thereof, and its supporting documentation for any
  purpose whatsoever, provided that this entire notice appears in all copies
  of the software, derivative works and supporting documentation.  Further,
  the user agrees to credit URI/MIT in any publications that result from the
  use of this software or in any product that includes this software. The
  names URI, MIT and/or GSO, however, may not be used in any advertising or
  publicity to endorse or promote any products or commercial entity unless
  specific written permission is obtained from URI/MIT. The user also
  understands that URI/MIT is not obligated to provide the user with any
  support, consulting, training or assistance of any kind with regard to the
  use, operation and performance of this software nor to provide the user
  with any updates, revisions, new versions or "bug fixes".

  THIS SOFTWARE IS PROVIDED BY URI/MIT "AS IS" AND ANY EXPRESS OR IMPLIED
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  EVENT SHALL URI/MIT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS
  ACTION, ARISING OUT OF OR IN CONNECTION WITH THE ACCESS, USE OR PERFORMANCE
  OF THIS SOFTWARE.
*/

// Implementation for Str.
//
// jhrg 9/7/94

// $Log: Str.cc,v $
// Revision 1.15  1995/08/23 00:18:30  jimg
// Now uses newer function names.
// Uses the new xdr_str() function in util.cc
//
// Revision 1.14  1995/07/09  21:29:04  jimg
// Added copyright notice.
//
// Revision 1.13  1995/05/10  15:34:05  jimg
// Failed to change `config.h' to `config_dap.h' in these files.
//
// Revision 1.12  1995/05/10  13:45:30  jimg
// Changed the name of the configuration header file from `config.h' to
// `config_dap.h' so that other libraries could have header files which were
// installed in the DODS include directory without overwriting this one. Each
// config header should follow the convention config_<name>.h.
//
// Revision 1.11  1995/03/16  17:26:41  jimg
// Moved include of config_dap.h to top of includes.
// Added TRACE_NEW switched dbnew debugging includes.
//
// Revision 1.10  1995/03/04  14:34:50  jimg
// Major modifications to the transmission and representation of values:
// 	Added card() virtual function which is true for classes that
// 	contain cardinal types (byte, int float, string).
// 	Changed the representation of Str from the C rep to a C++
// 	class represenation.
// 	Chnaged read_val and store_val so that they take and return
// 	types that are stored by the object (e.g., inthe case of Str
// 	an URL, read_val returns a C++ String object).
// 	Modified Array representations so that arrays of card()
// 	objects are just that - no more storing strings, ... as
// 	C would store them.
// 	Arrays of non cardinal types are arrays of the DODS objects (e.g.,
// 	an array of a structure is represented as an array of Structure
// 	objects).
//
// Revision 1.9  1995/02/10  02:22:49  jimg
// Added DBMALLOC includes and switch to code which uses malloc/free.
// Private and protected symbols now start with `_'.
// Added new accessors for name and type fields of BaseType; the old ones
// will be removed in a future release.
// Added the store_val() mfunc. It stores the given value in the object's
// internal buffer.
// Made both List and Str handle their values via pointers to memory.
// Fixed read_val().
// Made serialize/deserialize handle all malloc/free calls (even in those
// cases where xdr initiates the allocation).
// Fixed print_val().
//
// Revision 1.8  1995/01/19  20:05:19  jimg
// ptr_duplicate() mfunc is now abstract virtual.
// Array, ... Grid duplicate mfuncs were modified to take pointers, not
// referenves.
//
// Revision 1.7  1995/01/11  15:54:33  jimg
// Added modifications necessary for BaseType's static XDR pointers. This
// was mostly a name change from xdrin/out to _xdrin/out.
// Removed the two FILE pointers from ctors, since those are now set with
// functions which are friends of BaseType.
//
// Revision 1.6  1994/12/22  04:32:23  reza
// Changed the default type to String (from Str) to match DDS parser.
//
// Revision 1.5  1994/12/14  19:18:00  jimg
// Added mfunc len(). Replaced size() with a mfunc that returns the size of
// a pointer to a string (this simplifies Structure, ...).
//
// Revision 1.4  1994/12/14  18:04:33  jimg
// Changed definition of size() so that it returns the number of bytes in
// the string.
//
// Revision 1.3  1994/11/29  20:16:32  jimg
// Added mfunc for data transmission.
// Uses special xdr function for serialization and xdr_coder.
// Removed `type' parameter from ctor.
// Added FILE *in and *out to ctor parameter list.
//
// Revision 1.2  1994/09/23  14:36:12  jimg
// Fixed errors in comments.
//
// Revision 1.1  1994/09/15  21:08:48  jimg
// Added many classes to the BaseType hierarchy - the complete set of types
// described in the DODS API design documet is now represented.
// The parser can parse DDS files.
// Fixed many small problems with BaseType.
// Added CtorType.
//
// Revision 1.1  1994/09/09  15:38:45  jimg
// Child class of BaseType -- used in the future to hold specific serialization
// information for integers. Should this be a class that uses BaseType?
//

#ifdef __GNUG__
#pragma implementation
#endif

#include "config_dap.h"

#include <assert.h>
#include <string.h>

#include "Str.h"
#include "util.h"

#ifdef TRACE_NEW
#include "trace_new.h"
#endif

Str::Str(const String &n) : BaseType(n, str_t), _buf("")
{
}

// Return: the number of bytes needed to store the string's value or 0 if no
// storage for the string has been allocated.

unsigned int
Str::len()			// deprecated
{
    return length();
}

unsigned int
Str::length()
{
    return _buf.length();
}

#ifdef NEVER
bool
Str::card()
{
#ifdef NEVER
    return true;
#endif
    return false;
}
#endif

#ifdef NEVER
unsigned int
Str::size()			// deprecated
{
    return width();
}
#endif

// return the number of bytes that the value of a Str object occupies when
// that value is accessed using read_val().

unsigned int
Str::width()
{
    return sizeof(String);
}

// serialize and deserialize manage memory using malloc and free since, in
// some cases, they must let the xdr library (bundled with the CPU) do the
// allocation and that library will always use malloc/free.

bool
Str::serialize(bool flush)
{
#ifdef NEVER
    String *tmp = &_buf;	// kluge for xdr_str
#endif

    bool stat = (bool)xdr_str(_xdrout, _buf /* &tmp */);
    if (stat && flush)
	stat = expunge();

    return stat;
}

// deserialize the String on stdin and put the result in BUF.

bool
Str::deserialize(bool reuse)
{
#ifdef NEVER
    String *tmp = &_buf;
#endif

    return (bool)xdr_str(_xdrin, _buf /* &tmp */);
}

// Copy information in the object's internal buffers into the memory pointed
// to by VAL. If *VAL is null, then allocate memory for the value (a string
// in this case).
//
// NB: return the size of the thing val points to (sizeof val), not the
// length of the string. Thus if there is an array of of strings (i.e., (char
// *)s), then the return value of this mfunc can be used to advance to the
// next char * in that array. This weirdness is needed because C programs
// which will need to interface to libraries built using this toolkit will
// not know about g++ Strings and will need to use the C representation for
// strings, but here in the toolkit I use the String class to cut down on
// memory management problems.

unsigned int
Str::read_val(void **val)
{
    return buf2val(val);
}

unsigned int
Str::buf2val(void **val)
{
    assert(val);

    if (!*val)
	(String *)*val = new String(_buf);
    else
	*(String *)*val = _buf;

    return sizeof(String);
}

// Copy data in VAL to _BUF.
//
// Returns the number of bytes needed for _BUF (which is a pointer in this
// case).

unsigned int
Str::store_val(void *val, bool reuse)
{
    return val2buf(val, reuse);
}

unsigned int
Str::val2buf(void *val, bool reuse)
{
    assert(val);

    _buf = *(String *)val;

    return sizeof(String);
}

void
Str::print_val(ostream &os, String space, bool print_decl_p)
{
    if (print_decl_p) {
	print_decl(os, space, false);
	os << " = " << _buf << ";" << endl;
    }
    else
	os << _buf;
}

<|endoftext|>


<commit_before>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems              */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* ------------------------------------------------------------------------ */

#include "Document.h"
#include "OneDB.h"

using namespace std;

/* ************************************************************************ */
/* Document :: Constructor/Destructor                                       */
/* ************************************************************************ */

Document::Document( int id,
                    int _uid,
                    int _gid,
                    const string& _uname,
                    const string& _gname,
                    int _umask,
                    int _type,
                    std::unique_ptr<Template> _template_contents)
    : PoolObjectSQL(id,DOCUMENT,"",_uid,_gid,_uname,_gname,one_db::doc_table)
    , type(_type)
{
    if (_template_contents)
    {
        obj_template = make_unique<DocumentTemplate>(*_template_contents);
    }
    else
    {
        obj_template = make_unique<DocumentTemplate>();
    }

    set_umask(_umask);
}

/* ************************************************************************ */
/* Document :: Database Access Functions                                    */
/* ************************************************************************ */

int Document::insert(SqlDB *db, string& error_str)
{
    int             rc;
    ostringstream   oss;

    // ---------------------------------------------------------------------
    // Check default attributes
    // ---------------------------------------------------------------------

    erase_template_attribute("NAME", name);

    if ( name.empty() == true )
    {
        oss << "document-" << oid;
        name = oss.str();
    }
    else if ( name.length() > 128 )
    {
        error_str = "NAME is too long; max length is 128 chars.";
        return -1;
    }

    // Encrypt all the secrets
    encrypt();

    // ------------------------------------------------------------------------
    // Insert the Document
    // ------------------------------------------------------------------------

    rc = insert_replace(db, false, error_str);

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::insert_replace(SqlDB *db, bool replace, string& error_str)
{
    ostringstream   oss;

    int    rc;
    string xml_body;

    char * sql_name;
    char * sql_xml;

   // Update the Object

    sql_name = db->escape_str(name);

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body));

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if ( validate_xml(sql_xml) != 0 )
    {
        goto error_xml;
    }

    if(replace)
    {
        oss << "UPDATE " << one_db::doc_table << " SET "
            << "name = '"    << sql_name << "', "
            << "body = '"    << sql_xml  << "', "
            << "type = "     << type     << ", "
            << "uid = "      << uid      << ", "
            << "gid = "      << gid      << ", "
            << "owner_u = "  << owner_u  << ", "
            << "group_u = "  << group_u  << ", "
            << "other_u = "  << other_u
            << " WHERE oid = " << oid;
    }
    else
    {
        oss << "INSERT INTO " << one_db::doc_table
            << " (" << one_db::doc_db_names << ") VALUES ("
            <<            oid        << ","
            << "'"     << sql_name   << "',"
            << "'"     << sql_xml    << "',"
            <<            type       << ","
            <<            uid        << ","
            <<            gid        << ","
            <<            owner_u    << ","
            <<            group_u    << ","
            <<            other_u    << ")";
    }

    rc = db->exec_wr(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_xml:
    db->free_str(sql_name);
    db->free_str(sql_xml);

    error_str = "Error transforming the Document to XML.";

    goto error_common;

error_body:
    db->free_str(sql_name);
    goto error_generic;

error_name:
    goto error_generic;

error_generic:
    error_str = "Error inserting Document in DB.";
error_common:
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::bootstrap(SqlDB * db)
{
    ostringstream oss(one_db::doc_db_bootstrap);

    return db->exec_local_wr(oss);
}

/* ************************************************************************ */
/* Document :: Misc                                                         */
/* ************************************************************************ */

string& Document::to_xml(string& xml) const
{
    ostringstream   oss;
    string          template_xml;
    string          perm_str;
    string          lock_str;

    oss << "<DOCUMENT>"
            << "<ID>"       << oid        << "</ID>"
            << "<UID>"      << uid        << "</UID>"
            << "<GID>"      << gid        << "</GID>"
            << "<UNAME>"    << uname      << "</UNAME>"
            << "<GNAME>"    << gname      << "</GNAME>"
            << "<NAME>"     << name       << "</NAME>"
            << "<TYPE>"     << type       << "</TYPE>"
            << perms_to_xml(perm_str)
            << lock_db_to_xml(lock_str)
            << obj_template->to_xml(template_xml)
        << "</DOCUMENT>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::from_xml(const string& xml)
{
    vector<xmlNodePtr> content;
    int rc = 0;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid,        "/DOCUMENT/ID",      -1);
    rc += xpath(uid,        "/DOCUMENT/UID",     -1);
    rc += xpath(gid,        "/DOCUMENT/GID",     -1);
    rc += xpath(uname,      "/DOCUMENT/UNAME",   "not_found");
    rc += xpath(gname,      "/DOCUMENT/GNAME",   "not_found");
    rc += xpath(name,       "/DOCUMENT/NAME",    "not_found");
    rc += xpath(type,       "/DOCUMENT/TYPE",     0);

    // Permissions
    rc += perms_from_xml();

    // Lock info
    rc += lock_db_from_xml();

    // Get associated classes
    ObjectXML::get_nodes("/DOCUMENT/TEMPLATE", content);

    if (content.empty())
    {
        return -1;
    }

    // Template contents
    rc += obj_template->from_xml_node(content[0]);

    ObjectXML::free_nodes(content);

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}
<commit_msg>M #-: Document constructor, use move<commit_after>/* ------------------------------------------------------------------------ */
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems              */
/*                                                                          */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may  */
/* not use this file except in compliance with the License. You may obtain  */
/* a copy of the License at                                                 */
/*                                                                          */
/* http://www.apache.org/licenses/LICENSE-2.0                               */
/*                                                                          */
/* Unless required by applicable law or agreed to in writing, software      */
/* distributed under the License is distributed on an "AS IS" BASIS,        */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and      */
/* limitations under the License.                                           */
/* ------------------------------------------------------------------------ */

#include "Document.h"
#include "OneDB.h"

using namespace std;

/* ************************************************************************ */
/* Document :: Constructor/Destructor                                       */
/* ************************************************************************ */

Document::Document( int id,
                    int _uid,
                    int _gid,
                    const string& _uname,
                    const string& _gname,
                    int _umask,
                    int _type,
                    std::unique_ptr<Template> _template_contents)
    : PoolObjectSQL(id,DOCUMENT,"",_uid,_gid,_uname,_gname,one_db::doc_table)
    , type(_type)
{
    if (_template_contents)
    {
        obj_template = move(_template_contents);
    }
    else
    {
        obj_template = make_unique<DocumentTemplate>();
    }

    set_umask(_umask);
}

/* ************************************************************************ */
/* Document :: Database Access Functions                                    */
/* ************************************************************************ */

int Document::insert(SqlDB *db, string& error_str)
{
    int             rc;
    ostringstream   oss;

    // ---------------------------------------------------------------------
    // Check default attributes
    // ---------------------------------------------------------------------

    erase_template_attribute("NAME", name);

    if ( name.empty() == true )
    {
        oss << "document-" << oid;
        name = oss.str();
    }
    else if ( name.length() > 128 )
    {
        error_str = "NAME is too long; max length is 128 chars.";
        return -1;
    }

    // Encrypt all the secrets
    encrypt();

    // ------------------------------------------------------------------------
    // Insert the Document
    // ------------------------------------------------------------------------

    rc = insert_replace(db, false, error_str);

    return rc;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::insert_replace(SqlDB *db, bool replace, string& error_str)
{
    ostringstream   oss;

    int    rc;
    string xml_body;

    char * sql_name;
    char * sql_xml;

   // Update the Object

    sql_name = db->escape_str(name);

    if ( sql_name == 0 )
    {
        goto error_name;
    }

    sql_xml = db->escape_str(to_xml(xml_body));

    if ( sql_xml == 0 )
    {
        goto error_body;
    }

    if ( validate_xml(sql_xml) != 0 )
    {
        goto error_xml;
    }

    if(replace)
    {
        oss << "UPDATE " << one_db::doc_table << " SET "
            << "name = '"    << sql_name << "', "
            << "body = '"    << sql_xml  << "', "
            << "type = "     << type     << ", "
            << "uid = "      << uid      << ", "
            << "gid = "      << gid      << ", "
            << "owner_u = "  << owner_u  << ", "
            << "group_u = "  << group_u  << ", "
            << "other_u = "  << other_u
            << " WHERE oid = " << oid;
    }
    else
    {
        oss << "INSERT INTO " << one_db::doc_table
            << " (" << one_db::doc_db_names << ") VALUES ("
            <<            oid        << ","
            << "'"     << sql_name   << "',"
            << "'"     << sql_xml    << "',"
            <<            type       << ","
            <<            uid        << ","
            <<            gid        << ","
            <<            owner_u    << ","
            <<            group_u    << ","
            <<            other_u    << ")";
    }

    rc = db->exec_wr(oss);

    db->free_str(sql_name);
    db->free_str(sql_xml);

    return rc;

error_xml:
    db->free_str(sql_name);
    db->free_str(sql_xml);

    error_str = "Error transforming the Document to XML.";

    goto error_common;

error_body:
    db->free_str(sql_name);
    goto error_generic;

error_name:
    goto error_generic;

error_generic:
    error_str = "Error inserting Document in DB.";
error_common:
    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::bootstrap(SqlDB * db)
{
    ostringstream oss(one_db::doc_db_bootstrap);

    return db->exec_local_wr(oss);
}

/* ************************************************************************ */
/* Document :: Misc                                                         */
/* ************************************************************************ */

string& Document::to_xml(string& xml) const
{
    ostringstream   oss;
    string          template_xml;
    string          perm_str;
    string          lock_str;

    oss << "<DOCUMENT>"
            << "<ID>"       << oid        << "</ID>"
            << "<UID>"      << uid        << "</UID>"
            << "<GID>"      << gid        << "</GID>"
            << "<UNAME>"    << uname      << "</UNAME>"
            << "<GNAME>"    << gname      << "</GNAME>"
            << "<NAME>"     << name       << "</NAME>"
            << "<TYPE>"     << type       << "</TYPE>"
            << perms_to_xml(perm_str)
            << lock_db_to_xml(lock_str)
            << obj_template->to_xml(template_xml)
        << "</DOCUMENT>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int Document::from_xml(const string& xml)
{
    vector<xmlNodePtr> content;
    int rc = 0;

    // Initialize the internal XML object
    update_from_str(xml);

    // Get class base attributes
    rc += xpath(oid,        "/DOCUMENT/ID",      -1);
    rc += xpath(uid,        "/DOCUMENT/UID",     -1);
    rc += xpath(gid,        "/DOCUMENT/GID",     -1);
    rc += xpath(uname,      "/DOCUMENT/UNAME",   "not_found");
    rc += xpath(gname,      "/DOCUMENT/GNAME",   "not_found");
    rc += xpath(name,       "/DOCUMENT/NAME",    "not_found");
    rc += xpath(type,       "/DOCUMENT/TYPE",     0);

    // Permissions
    rc += perms_from_xml();

    // Lock info
    rc += lock_db_from_xml();

    // Get associated classes
    ObjectXML::get_nodes("/DOCUMENT/TEMPLATE", content);

    if (content.empty())
    {
        return -1;
    }

    // Template contents
    rc += obj_template->from_xml_node(content[0]);

    ObjectXML::free_nodes(content);

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>#ifndef ENTT_CORE_MEMORY_HPP
#define ENTT_CORE_MEMORY_HPP

#include <cstddef>
#include <limits>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"

namespace entt {

/**
 * @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
 * @tparam Type Pointer type.
 * @param ptr Fancy or raw pointer.
 * @return A raw pointer that represents the address of the original pointer.
 */
template<typename Type>
[[nodiscard]] constexpr auto to_address(Type &&ptr) ENTT_NOEXCEPT {
    if constexpr(std::is_pointer_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
        return ptr;
    } else {
        return to_address(std::forward<Type>(ptr).operator->());
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
        lhs = rhs;
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
        lhs = std::move(rhs);
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    ENTT_ASSERT(std::allocator_traits<Allocator>::propagate_on_container_swap::value || lhs == rhs, "Cannot swap the containers");

    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
        using std::swap;
        swap(lhs, rhs);
    }
}

/**
 * @brief Checks whether a value is a power of two or not.
 * @param value A value that may or may not be a power of two.
 * @return True if the value is a power of two, false otherwise.
 */
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
    return value && ((value & (value - 1)) == 0);
}

/**
 * @brief Computes the smallest power of two greater than or equal to a value.
 * @param value The value to use.
 * @return The smallest power of two greater than or equal to the given value.
 */
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
    ENTT_ASSERT(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
    std::size_t curr = value - (value != 0u);

    for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
        curr |= curr >> next;
    }

    return ++curr;
}

/**
 * @brief Fast module utility function (powers of two only).
 * @param value A value for which to calculate the modulus.
 * @param mod _Modulus_, it must be a power of two.
 * @return The common remainder.
 */
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) ENTT_NOEXCEPT {
    ENTT_ASSERT(is_power_of_two(mod), "Value must be a power of two");
    return value & (mod - 1u);
}

/**
 * @brief Deleter for allocator-aware unique pointers (waiting for C++20).
 * @tparam Args Types of arguments to use to construct the object.
 */
template<typename Allocator>
struct allocation_deleter: private Allocator {
    /*! @brief Allocator type. */
    using allocator_type = Allocator;
    /*! @brief Pointer type. */
    using pointer = typename std::allocator_traits<Allocator>::pointer;

    /**
     * @brief Inherited constructors.
     * @param alloc The allocator to use.
     */
    allocation_deleter(const allocator_type &alloc)
        : Allocator{alloc} {}

    /**
     * @brief Destroys the pointed object and deallocates its memory.
     * @param ptr A valid pointer to an object of the given type.
     */
    void operator()(pointer ptr) {
        using alloc_traits = typename std::allocator_traits<Allocator>;
        alloc_traits::destroy(*this, to_address(ptr));
        alloc_traits::deallocate(*this, ptr, 1u);
    }
};

/**
 * @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
 * @tparam Type Type of object to allocate for and to construct.
 * @tparam Allocator Type of allocator used to manage memory and elements.
 * @tparam Args Types of arguments to use to construct the object.
 * @param allocator The allocator to use.
 * @param args Parameters to use to construct an object for the entity.
 * @return A properly initialized unique pointer with a custom deleter.
 */
template<typename Type, typename Allocator, typename... Args>
auto allocate_unique(Allocator &allocator, Args &&...args) {
    static_assert(!std::is_array_v<Type>, "Array types are not supported");

    using alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<Type>;
    using alloc_traits = typename std::allocator_traits<alloc>;

    alloc type_allocator{allocator};
    auto ptr = alloc_traits::allocate(type_allocator, 1u);

    ENTT_TRY {
        alloc_traits::construct(type_allocator, to_address(ptr), std::forward<Args>(args)...);
    }
    ENTT_CATCH {
        alloc_traits::deallocate(type_allocator, ptr, 1u);
        ENTT_THROW;
    }

    return std::unique_ptr<Type, allocation_deleter<alloc>>{ptr, type_allocator};
}

} // namespace entt

#endif
<commit_msg>doc: minor changes<commit_after>#ifndef ENTT_CORE_MEMORY_HPP
#define ENTT_CORE_MEMORY_HPP

#include <cstddef>
#include <limits>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"

namespace entt {

/**
 * @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
 * @tparam Type Pointer type.
 * @param ptr Fancy or raw pointer.
 * @return A raw pointer that represents the address of the original pointer.
 */
template<typename Type>
[[nodiscard]] constexpr auto to_address(Type &&ptr) ENTT_NOEXCEPT {
    if constexpr(std::is_pointer_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
        return ptr;
    } else {
        return to_address(std::forward<Type>(ptr).operator->());
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
        lhs = rhs;
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
        lhs = std::move(rhs);
    }
}

/**
 * @brief Utility function to design allocation-aware containers.
 * @tparam Allocator Type of allocator.
 * @param lhs A valid allocator.
 * @param rhs Another valid allocator.
 */
template<typename Allocator>
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
    ENTT_ASSERT(std::allocator_traits<Allocator>::propagate_on_container_swap::value || lhs == rhs, "Cannot swap the containers");

    if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
        using std::swap;
        swap(lhs, rhs);
    }
}

/**
 * @brief Checks whether a value is a power of two or not.
 * @param value A value that may or may not be a power of two.
 * @return True if the value is a power of two, false otherwise.
 */
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
    return value && ((value & (value - 1)) == 0);
}

/**
 * @brief Computes the smallest power of two greater than or equal to a value.
 * @param value The value to use.
 * @return The smallest power of two greater than or equal to the given value.
 */
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
    ENTT_ASSERT(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
    std::size_t curr = value - (value != 0u);

    for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
        curr |= curr >> next;
    }

    return ++curr;
}

/**
 * @brief Fast module utility function (powers of two only).
 * @param value A value for which to calculate the modulus.
 * @param mod _Modulus_, it must be a power of two.
 * @return The common remainder.
 */
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) ENTT_NOEXCEPT {
    ENTT_ASSERT(is_power_of_two(mod), "Value must be a power of two");
    return value & (mod - 1u);
}

/**
 * @brief Deleter for allocator-aware unique pointers (waiting for C++20).
 * @tparam Args Types of arguments to use to construct the object.
 */
template<typename Allocator>
struct allocation_deleter: private Allocator {
    /*! @brief Allocator type. */
    using allocator_type = Allocator;
    /*! @brief Pointer type. */
    using pointer = typename std::allocator_traits<Allocator>::pointer;

    /**
     * @brief Inherited constructors.
     * @param alloc The allocator to use.
     */
    allocation_deleter(const allocator_type &alloc)
        : Allocator{alloc} {}

    /**
     * @brief Destroys the pointed object and deallocates its memory.
     * @param ptr A valid pointer to an object of the given type.
     */
    void operator()(pointer ptr) {
        using alloc_traits = typename std::allocator_traits<Allocator>;
        alloc_traits::destroy(*this, to_address(ptr));
        alloc_traits::deallocate(*this, ptr, 1u);
    }
};

/**
 * @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
 * @tparam Type Type of object to allocate for and to construct.
 * @tparam Allocator Type of allocator used to manage memory and elements.
 * @tparam Args Types of arguments to use to construct the object.
 * @param allocator The allocator to use.
 * @param args Parameters to use to construct the object.
 * @return A properly initialized unique pointer with a custom deleter.
 */
template<typename Type, typename Allocator, typename... Args>
auto allocate_unique(Allocator &allocator, Args &&...args) {
    static_assert(!std::is_array_v<Type>, "Array types are not supported");

    using alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<Type>;
    using alloc_traits = typename std::allocator_traits<alloc>;

    alloc type_allocator{allocator};
    auto ptr = alloc_traits::allocate(type_allocator, 1u);

    ENTT_TRY {
        alloc_traits::construct(type_allocator, to_address(ptr), std::forward<Args>(args)...);
    }
    ENTT_CATCH {
        alloc_traits::deallocate(type_allocator, ptr, 1u);
        ENTT_THROW;
    }

    return std::unique_ptr<Type, allocation_deleter<alloc>>{ptr, type_allocator};
}

} // namespace entt

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2021 Roberto Raggi <roberto.raggi@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <cxx/ast.h>
#include <cxx/ast_visitor.h>
#include <cxx/control.h>
#include <cxx/lexer.h>
#include <cxx/translation_unit.h>
#include <fmt/format.h>
#include <fmt/ostream.h>

#include <cassert>
#include <fstream>
#include <iostream>
#include <string>

namespace cxx {

std::string readAll(const std::string& fileName, std::istream& in) {
  std::string code;
  char buffer[4 * 1024];
  do {
    in.read(buffer, sizeof(buffer));
    code.append(buffer, in.gcount());
  } while (in);
  return code;
}

std::string readAll(const std::string& fileName) {
  if (fileName == "-" || fileName.empty()) return readAll("<stdin>", std::cin);
  std::ifstream stream(fileName);
  return readAll(fileName, stream);
}

bool parseFile(const std::string& fileName) {
  Control control;
  TranslationUnit unit(&control);
  unit.setFileName(fileName);
  unit.setSource(readAll(fileName));
  const auto result = unit.parse();
  return result;
}

}  // namespace cxx

int main(int argc, char* argv[]) {
  using namespace cxx;

  std::vector<std::string> inputFiles;
  bool dumpTokens = false;

  int index = 1;
  while (index < argc) {
    std::string arg{argv[index++]};
    if (arg == "--help") {
      std::cerr << "Usage: cplusplus [options] files..." << std::endl
                << " The options are:" << std::endl
                << "  --help            display this output" << std::endl
                << "  -dump-tokens      dump tokens" << std::endl;
      exit(EXIT_SUCCESS);
    } else if (arg == "--dump-tokens") {
      dumpTokens = true;
    } else {
      inputFiles.push_back(std::move(arg));
    }
  }

  if (inputFiles.empty()) {
    std::cerr << "cplusplus: no input files" << std::endl
              << "Usage: cplusplus [options] files..." << std::endl;
    return EXIT_FAILURE;
  }

  for (const auto& fileName : inputFiles) {
    if (dumpTokens) {
      const auto source = readAll(fileName);
      Lexer lexer(source);
      lexer.setPreprocessing(true);

      do {
        lexer.next();

        std::string flags;

        if (lexer.tokenStartOfLine()) {
          flags += " [start-of-line]";
        }

        if (lexer.tokenLeadingSpace()) {
          flags += " [leading-space]";
        }

        fmt::print("{} '{}'{}\n", Token::name(lexer.tokenKind()),
                   lexer.tokenText(), flags);
      } while (lexer.tokenKind() != TokenKind::T_EOF_SYMBOL);
      continue;
    }

    parseFile(fileName);
  }

  return EXIT_SUCCESS;
}
<commit_msg>Add --dump-ast<commit_after>// Copyright (c) 2021 Roberto Raggi <roberto.raggi@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <cxx/ast.h>
#include <cxx/ast_visitor.h>
#include <cxx/control.h>
#include <cxx/lexer.h>
#include <cxx/recursive_ast_visitor.h>
#include <cxx/translation_unit.h>
#include <fmt/format.h>
#include <fmt/ostream.h>

#include <cassert>
#include <fstream>
#include <iostream>
#include <string>

#if defined(__has_include)
#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
#define WITH_CXXABI
#endif
#endif

namespace cxx {

class DumpAST final : RecursiveASTVisitor {
  TranslationUnit* unit_;
  int depth_ = 0;

  bool preVisit(AST* ast) override {
    std::string ind(depth_ * 2, ' ');

    std::string_view name = typeid(*ast).name();

#ifdef WITH_CXXABI
    int status = 0;
    auto mangled = abi::__cxa_demangle(name.data(), nullptr, 0, &status);
    name = mangled;
#endif

#if 0
    if (ast->firstSourceLocation())
      unit_->report(ast->firstSourceLocation(), Severity::Message, "{}{}", ind,
                    name);
#else
    fmt::print("{}{}\n", ind, name);
#endif

#ifdef WITH_CXXABI
    std::free(mangled);
#endif

    ++depth_;

    return true;
  }

  void postVisit(AST*) override { --depth_; }

 public:
  explicit DumpAST(TranslationUnit* unit) : unit_(unit) {}

  void operator()() { accept(unit_->ast()); }
};

std::string readAll(const std::string& fileName, std::istream& in) {
  std::string code;
  char buffer[4 * 1024];
  do {
    in.read(buffer, sizeof(buffer));
    code.append(buffer, in.gcount());
  } while (in);
  return code;
}

std::string readAll(const std::string& fileName) {
  if (fileName == "-" || fileName.empty()) return readAll("<stdin>", std::cin);
  std::ifstream stream(fileName);
  return readAll(fileName, stream);
}

bool parseFile(const std::string& fileName, bool printAST) {
  Control control;
  TranslationUnit unit(&control);
  unit.setFileName(fileName);
  unit.setSource(readAll(fileName));
  const auto result = unit.parse();
  if (printAST) {
    DumpAST dump(&unit);
    dump();
  }
  return result;
}

}  // namespace cxx

int main(int argc, char* argv[]) {
  using namespace cxx;

  std::vector<std::string> inputFiles;
  bool dumpTokens = false;
  bool dumpAST = false;

  int index = 1;
  while (index < argc) {
    std::string arg{argv[index++]};
    if (arg == "--help") {
      std::cerr << "Usage: cplusplus [options] files..." << std::endl
                << " The options are:" << std::endl
                << "  --help            display this output" << std::endl
                << "  -dump-tokens      dump tokens" << std::endl
                << "  -dump-ast         dump AST" << std::endl;
      exit(EXIT_SUCCESS);
    } else if (arg == "--dump-tokens") {
      dumpTokens = true;
    } else if (arg == "--dump-ast") {
      dumpAST = true;
    } else {
      inputFiles.push_back(std::move(arg));
    }
  }

  if (inputFiles.empty()) {
    std::cerr << "cplusplus: no input files" << std::endl
              << "Usage: cplusplus [options] files..." << std::endl;
    return EXIT_FAILURE;
  }

  for (const auto& fileName : inputFiles) {
    if (dumpTokens) {
      const auto source = readAll(fileName);
      Lexer lexer(source);
      lexer.setPreprocessing(true);

      do {
        lexer.next();

        std::string flags;

        if (lexer.tokenStartOfLine()) {
          flags += " [start-of-line]";
        }

        if (lexer.tokenLeadingSpace()) {
          flags += " [leading-space]";
        }

        fmt::print("{} '{}'{}\n", Token::name(lexer.tokenKind()),
                   lexer.tokenText(), flags);
      } while (lexer.tokenKind() != TokenKind::T_EOF_SYMBOL);
      continue;
    }

    parseFile(fileName, dumpAST);
  }

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*
 * XCFun, an arbitrary order exchange-correlation library
 * Copyright (C) 2020 Ulf Ekström and contributors.
 *
 * This file is part of XCFun.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * For information on the complete list of contributors to the
 * XCFun library, see: <https://xcfun.readthedocs.io/>
 */

#include "constants.hpp"
#include "functional.hpp"
#include "pz81c.hpp"

template <typename num> static num Cg(const num & r) {
  parameter Cx = 0.001667;
  parameter Bg = 0.000007389;
  return Cx + (0.002568 + r * (0.023266 + Bg * r)) /
                  (1 + r * (8.723 + r * (0.472 + 10000 * Bg * r)));
}

template <typename num> static num Pg(const densvars<num> & d) {
  parameter Fg = 0.11;
  parameter Cinf = 0.004235;
  parameter fudge = 1e-12; // Avoid instability at d.gnn = 0
#ifndef INEXACT_PI
  parameter pi_expr = pow(9 * M_PI, 1.0 / 6.0);
#else
  parameter pi_expr = 1.745;
#endif
  return pi_expr * Fg * Cinf * sqrt(fudge + d.gnn) /
         (Cg(d.r_s) * pow(d.n, 7.0 / 6.0));
}

template <typename num> static num dz(const densvars<num> & d) {
  return cbrt(2.0) * sqrt(pow(d.a, 5.0 / 3.0) + pow(d.b, 5.0 / 3.0)) *
         pow(d.n, -5.0 / 6.0);
}

template <typename num> static num p86c(const densvars<num> & d) {
  return d.n * pz81eps::pz81eps(d) +
         exp(-Pg(d)) * Cg(d.r_s) * d.gnn / (pow(d.n, 4.0 / 3.0) * dz(d));
}

template <typename num> static num p86c_corr(const densvars<num> & d) {
  return exp(-Pg(d)) * Cg(d.r_s) * d.gnn / (pow(d.n, 4.0 / 3.0) * dz(d));
}

FUNCTIONAL(XC_P86C) = {
    "P86C GGA correlation",
    "J.P. Density-functional approximation for the correlation energy\n"
    "of the inhomogeneous electron , Phys. Rev. B, 33(12):8822gasPerdew,\n"
    "Implemented by Ulf Ekstrom.\n"
    "Reference data from ftp://ftp.dl.ac.uk/qcg/dft_library/data_pt_c_p86.html",
    XC_DENSITY | XC_GRADIENT,
    ENERGY_FUNCTION(p86c) XC_A_B_GAA_GAB_GBB,
    XC_PARTIAL_DERIVATIVES,
    2,
    1e-10,
#ifdef HIGH_DENSITY
    {0.39E+02, 0.38E+02, 0.81E+06, 0.82E+06, 0.82E+06},
#ifdef INEXACT_PI
    {
        -0.356963343227E+01, -0.433530899660E-01, -0.447602011737E-01,
        -0.122488989075E-06, -0.244977978150E-06, -0.122488989075E-06,
        -0.169450157064E-02, -0.308422706942E-02, 0.227151852191E-07,
        0.454303704383E-07,  0.227151852191E-07,  -0.165896811718E-02,
        0.226922323054E-07,  0.453844646108E-07,  0.226922323054E-07,
        -0.207808284633E-12, -0.415616569266E-12, -0.207808284633E-12,
        -0.831233138532E-12, -0.415616569266E-12, -0.207808284633E-12,
    }
#else
    {
        -3.5721593740706306e+00, -4.3353602806095654e-02, -4.4761187343925160e-02,
        -1.2281210551047686e-07, -2.4562421102095372e-07, -1.2281210551047686e-07,
        -1.6930136257204879e-03, -3.0832001805399236e-03, +2.2702465560744966e-08,
        +4.5404931121489932e-08, +2.2702465560744966e-08, -1.6574558665771906e-03,
        +2.2679452099010038e-08, +4.5358904198020076e-08, +2.2679452099010038e-08,
        -2.0762304168807950e-13, -4.1524608337615900e-13, -2.0762304168807950e-13,
        -8.3049216675231800e-13, -4.1524608337615900e-13, -2.0762304168807950e-13,
    }
#endif
#else
    {0.48E-01, 0.25E-01, 0.46E-02, 0.44E-02, 0.41E-02},
#ifdef INEXACT_PI
    {-0.227465804486E-02, -0.607101652780E-01, -0.809996785446E-01,
     0.542965890398E-01,  0.108593178080E+00,  0.542965890398E-01,
     0.329942643730E+00,  -0.517763280120E+00, -0.232199446020E+00,
     -0.464398892040E+00, -0.232199446020E+00, 0.564642641219E+00,
     0.164136266720E-01,  0.328272533439E-01,  0.164136266720E-01,
     -0.145741442973E+01, -0.291482885947E+01, -0.145741442973E+01,
     -0.582965771894E+01, -0.291482885947E+01, -0.145741442973E+01}
#else // self-computed values
    {
        -2.2748317487871362e-03, -6.0705512544759296e-02, -8.0995821166401388e-02,
        +5.4284455865926534e-02, +1.0856891173185307e-01, +5.4284455865926534e-02,
        +3.2978359263409207e-01, -5.1791169779733182e-01, -2.3191926560979093e-01,
        -4.6383853121958185e-01, -2.3191926560979093e-01, +5.6456418726387536e-01,
        +1.6638251739185206e-02, +3.3276503478370412e-02, +1.6638251739185206e-02,
        -1.4574898694069474e+00, -2.9149797388138947e+00, -1.4574898694069474e+00,
        -5.8299594776277894e+00, -2.9149797388138947e+00, -1.4574898694069474e+00,
    }
#endif
#endif
};

FUNCTIONAL(XC_P86CORRC) = {
    "P86C GGA correlation",
    "J.P. Density-functional approximation for the correlation energy\n"
    "of the inhomogeneous electron , Phys. Rev. B, 33(12):8822gasPerdew,\n"
    "Implemented by Ulf Ekstrom.\n"
    "Reference data from ftp://ftp.dl.ac.uk/qcg/dft_library/data_pt_c_p86.html",
    XC_DENSITY | XC_GRADIENT,
    ENERGY_FUNCTION(p86c_corr)};
<commit_msg>Fix reference for P86C (#160)<commit_after>/*
 * XCFun, an arbitrary order exchange-correlation library
 * Copyright (C) 2020 Ulf Ekström and contributors.
 *
 * This file is part of XCFun.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * For information on the complete list of contributors to the
 * XCFun library, see: <https://xcfun.readthedocs.io/>
 */

#include "constants.hpp"
#include "functional.hpp"
#include "pz81c.hpp"

template <typename num> static num Cg(const num & r) {
  parameter Cx = 0.001667;
  parameter Bg = 0.000007389;
  return Cx + (0.002568 + r * (0.023266 + Bg * r)) /
                  (1 + r * (8.723 + r * (0.472 + 10000 * Bg * r)));
}

template <typename num> static num Pg(const densvars<num> & d) {
  parameter Fg = 0.11;
  parameter Cinf = 0.004235;
  parameter fudge = 1e-12; // Avoid instability at d.gnn = 0
#ifndef INEXACT_PI
  parameter pi_expr = pow(9 * M_PI, 1.0 / 6.0);
#else
  parameter pi_expr = 1.745;
#endif
  return pi_expr * Fg * Cinf * sqrt(fudge + d.gnn) /
         (Cg(d.r_s) * pow(d.n, 7.0 / 6.0));
}

template <typename num> static num dz(const densvars<num> & d) {
  return cbrt(2.0) * sqrt(pow(d.a, 5.0 / 3.0) + pow(d.b, 5.0 / 3.0)) *
         pow(d.n, -5.0 / 6.0);
}

template <typename num> static num p86c(const densvars<num> & d) {
  return d.n * pz81eps::pz81eps(d) +
         exp(-Pg(d)) * Cg(d.r_s) * d.gnn / (pow(d.n, 4.0 / 3.0) * dz(d));
}

template <typename num> static num p86c_corr(const densvars<num> & d) {
  return exp(-Pg(d)) * Cg(d.r_s) * d.gnn / (pow(d.n, 4.0 / 3.0) * dz(d));
}

FUNCTIONAL(XC_P86C) = {
    "P86C GGA correlation",
    "J.P. Density-functional approximation for the correlation energy\n"
    "of the inhomogeneous electron , Phys. Rev. B, 33(12):8822gasPerdew,\n"
    "Implemented by Ulf Ekstrom.\n"
    "Reference data from ftp://ftp.dl.ac.uk/qcg/dft_library/data_pt_c_p86.html",
    XC_DENSITY | XC_GRADIENT,
    ENERGY_FUNCTION(p86c) XC_A_B_GAA_GAB_GBB,
    XC_PARTIAL_DERIVATIVES,
    2,
    1e-10,
#ifdef HIGH_DENSITY
    {0.39E+02, 0.38E+02, 0.81E+06, 0.82E+06, 0.82E+06},
#ifdef INEXACT_PI
    {
        -0.356963343227E+01, -0.433530899660E-01, -0.447602011737E-01,
        -0.122488989075E-06, -0.244977978150E-06, -0.122488989075E-06,
        -0.169450157064E-02, -0.308422706942E-02, 0.227151852191E-07,
        0.454303704383E-07,  0.227151852191E-07,  -0.165896811718E-02,
        0.226922323054E-07,  0.453844646108E-07,  0.226922323054E-07,
        -0.207808284633E-12, -0.415616569266E-12, -0.207808284633E-12,
        -0.831233138532E-12, -0.415616569266E-12, -0.207808284633E-12,
    }
#else
    {
        -3.5721593740706306e+00, -4.3353602806095654e-02, -4.4761187343925160e-02,
        -1.2281210551047686e-07, -2.4562421102095372e-07, -1.2281210551047686e-07,
        -1.6930136257204879e-03, -3.0832001805399236e-03, +2.2702465560744966e-08,
        +4.5404931121489932e-08, +2.2702465560744966e-08, -1.6574558665771906e-03,
        +2.2679452099010038e-08, +4.5358904198020076e-08, +2.2679452099010038e-08,
        -2.0762304168807950e-13, -4.1524608337615900e-13, -2.0762304168807950e-13,
        -8.3049216675231800e-13, -4.1524608337615900e-13, -2.0762304168807950e-13,
    }
#endif
#else
    {0.48E-01, 0.25E-01, 0.46E-02, 0.44E-02, 0.41E-02},
#ifdef INEXACT_PI
    {-0.227465804486E-02, -0.607101652780E-01, -0.809996785446E-01,
     0.542965890398E-01,  0.108593178080E+00,  0.542965890398E-01,
     0.329942643730E+00,  -0.517763280120E+00, -0.232199446020E+00,
     -0.464398892040E+00, -0.232199446020E+00, 0.564642641219E+00,
     0.164136266720E-01,  0.328272533439E-01,  0.164136266720E-01,
     -0.145741442973E+01, -0.291482885947E+01, -0.145741442973E+01,
     -0.582965771894E+01, -0.291482885947E+01, -0.145741442973E+01}
#else // self-computed values
    {
        -2.2748317487871362e-03, -6.0705512544759296e-02, -8.0995821166401388e-02,
        +5.4284455865926534e-02, +1.0856891173185307e-01, +5.4284455865926534e-02,
        +3.2978359263409207e-01, -5.1791169779733182e-01, -2.3191926560979093e-01,
        -4.6383853121958185e-01, -2.3191926560979093e-01, +5.6456418726387536e-01,
        +1.6638251739185206e-02, +3.3276503478370412e-02, +1.6638251739185206e-02,
        -1.4574898694069474e+00, -2.9149797388138947e+00, -1.4574898694069474e+00,
        -5.8299594776277894e+00, -2.9149797388138947e+00, -1.4574898694069474e+00,
    }
#endif
#endif
};

FUNCTIONAL(XC_P86CORRC) = {
    "P86C GGA correlation",
    "J. P. Perdew, Density-functional approximation for the correlation energy\n"
    "of the inhomogeneous electron, Phys. Rev. B 33, 8822 (1986).\n"
    "Implemented by Ulf Ekstrom.\n"
    "Reference data from ftp://ftp.dl.ac.uk/qcg/dft_library/data_pt_c_p86.html",
    XC_DENSITY | XC_GRADIENT,
    ENERGY_FUNCTION(p86c_corr)};
<|endoftext|>


<commit_before>#include "world.hpp"
#include "entity.hpp"
#include "thinker.hpp"
#include "stars.hpp"
#include "opengl.hpp"
#include "player.hpp"
namespace Space {

struct World::Event {
    enum Type {
        EntityAdd,
        EntityRemove,
        ThinkerAdd,
        ThinkerRemove
    };

    Type t;
    void *o;

    Event(Type tt, Entity *oo)
        : t(tt), o(reinterpret_cast<void*>(oo))
    { }

    Event(Type tt, Thinker *oo)
        : t(tt), o(reinterpret_cast<void*>(oo))
    { }

    Entity *asEntity() const
    {
        return reinterpret_cast<Entity*>(o);
    }

    Thinker *asThinker() const
    {
        return reinterpret_cast<Thinker *>(o);
    }
};

World::World()
  : time_(0.0)
{
    starfields_.resize(9);
    for (int i = 0; i < 9; ++i) {
        starfields_[i].parallax = 0.1 * (i + 1);
        starfields_[i].tileSize = 64.0;
    }
}

World::~World()
{
    for (std::set<Entity*>::iterator
             i = entities_.begin(), e = entities_.end();
         i != e; ++i)
        delete *i;
    for (std::set<Thinker*>::iterator
             i = thinkers_.begin(), e = thinkers_.end();
         i != e; ++i)
        delete *i;
}

void World::update(unsigned ticks)
{
    double new_time = 0.001 * ticks;
    double delta = new_time - time_;
    time_ = new_time;
    for (unsigned int i = 0; i < events_.size(); ++i) {
        Event &evt = events_[i];
        Entity *e = evt.asEntity();
        Thinker *t = evt.asThinker();
        switch (evt.t) {
        case Event::EntityAdd:
            entities_.insert(e);
            break;
        case Event::EntityRemove:
            if (entities_.erase(e))
                delete e;
            break;
        case Event::ThinkerAdd:
            thinkers_.insert(t);
            t->enterGame(*this);
            break;
        case Event::ThinkerRemove:
            t->leaveGame(*this);
            if (thinkers_.erase(t))
                delete t;
            break;
        }
    }
    events_.clear();
    for (std::set<Thinker *>::iterator
             i = thinkers_.begin(),
             e = thinkers_.end();
         i != e; ++i) {
        Thinker &a = **i;
        a.think(*this, delta);
    }
    for (std::set<Entity*>::iterator
             i = entities_.begin(),
             e = entities_.end();
         i != e; ++i) {
        Entity &a = **i;
        a.move(*this, delta);
    }
}

void World::draw()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-320.0, 320.0, -240.0, 240.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);

    vector loc = player_->location();
    glLoadIdentity();
    glTranslatef(-loc.v[0], -loc.v[1], 0.0f);

    for (std::vector<Starfield>::iterator
             i = starfields_.begin(), e = starfields_.end();
         i != e; ++i)
        i->draw(loc.v[0] - 320.0, loc.v[1] - 240.0, 640.0, 480.0);

    for (std::set<Entity*>::iterator
             i = entities_.begin(),
             e = entities_.end();
         i != e; ++i)
        (*i)->draw();
}

void World::addEntity(Entity *e)
{
    events_.push_back(Event(Event::EntityAdd, e));
}

void World::removeEntity(Entity *e)
{
    events_.push_back(Event(Event::EntityRemove, e));
}

void World::addThinker(Thinker* t)
{
    events_.push_back(Event(Event::ThinkerRemove, t));
}

void World::removeThinker(Thinker* t)
{
    events_.push_back(Event(Event::ThinkerRemove, t));
}

}
<commit_msg>Fix aspect ratio of space game<commit_after>#include "world.hpp"
#include "entity.hpp"
#include "thinker.hpp"
#include "stars.hpp"
#include "opengl.hpp"
#include "player.hpp"
#include "graphics/video.hpp"
namespace Space {

struct World::Event {
    enum Type {
        EntityAdd,
        EntityRemove,
        ThinkerAdd,
        ThinkerRemove
    };

    Type t;
    void *o;

    Event(Type tt, Entity *oo)
        : t(tt), o(reinterpret_cast<void*>(oo))
    { }

    Event(Type tt, Thinker *oo)
        : t(tt), o(reinterpret_cast<void*>(oo))
    { }

    Entity *asEntity() const
    {
        return reinterpret_cast<Entity*>(o);
    }

    Thinker *asThinker() const
    {
        return reinterpret_cast<Thinker *>(o);
    }
};

World::World()
  : time_(0.0)
{
    starfields_.resize(9);
    for (int i = 0; i < 9; ++i) {
        starfields_[i].parallax = 0.1 * (i + 1);
        starfields_[i].tileSize = 64.0;
    }
}

World::~World()
{
    for (std::set<Entity*>::iterator
             i = entities_.begin(), e = entities_.end();
         i != e; ++i)
        delete *i;
    for (std::set<Thinker*>::iterator
             i = thinkers_.begin(), e = thinkers_.end();
         i != e; ++i)
        delete *i;
}

void World::update(unsigned ticks)
{
    double new_time = 0.001 * ticks;
    double delta = new_time - time_;
    time_ = new_time;
    for (unsigned int i = 0; i < events_.size(); ++i) {
        Event &evt = events_[i];
        Entity *e = evt.asEntity();
        Thinker *t = evt.asThinker();
        switch (evt.t) {
        case Event::EntityAdd:
            entities_.insert(e);
            break;
        case Event::EntityRemove:
            if (entities_.erase(e))
                delete e;
            break;
        case Event::ThinkerAdd:
            thinkers_.insert(t);
            t->enterGame(*this);
            break;
        case Event::ThinkerRemove:
            t->leaveGame(*this);
            if (thinkers_.erase(t))
                delete t;
            break;
        }
    }
    events_.clear();
    for (std::set<Thinker *>::iterator
             i = thinkers_.begin(),
             e = thinkers_.end();
         i != e; ++i) {
        Thinker &a = **i;
        a.think(*this, delta);
    }
    for (std::set<Entity*>::iterator
             i = entities_.begin(),
             e = entities_.end();
         i != e; ++i) {
        Entity &a = **i;
        a.move(*this, delta);
    }
}

void World::draw()
{
    int w = Video::width, h = Video::height;
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-w/2, w-w/2, -h/2, h-h/2, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);

    vector loc = player_->location();
    glLoadIdentity();
    glTranslatef(-loc.v[0], -loc.v[1], 0.0f);

    for (std::vector<Starfield>::iterator
             i = starfields_.begin(), e = starfields_.end();
         i != e; ++i)
        i->draw(loc.v[0] - w/2, loc.v[1] - h/2, w, h);

    for (std::set<Entity*>::iterator
             i = entities_.begin(),
             e = entities_.end();
         i != e; ++i)
        (*i)->draw();
}

void World::addEntity(Entity *e)
{
    events_.push_back(Event(Event::EntityAdd, e));
}

void World::removeEntity(Entity *e)
{
    events_.push_back(Event(Event::EntityRemove, e));
}

void World::addThinker(Thinker* t)
{
    events_.push_back(Event(Event::ThinkerRemove, t));
}

void World::removeThinker(Thinker* t)
{
    events_.push_back(Event(Event::ThinkerRemove, t));
}

}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_validate.cpp
 *
 * Attempts to verify that various invariants of the IR tree are true.
 *
 * In particular, at the moment it makes sure that no single
 * ir_instruction node except for ir_variable appears multiple times
 * in the ir tree.  ir_variable does appear multiple times: Once as a
 * declaration in an exec_list, and multiple times as the endpoint of
 * a dereference chain.
 */

#include <inttypes.h>
#include "ir.h"
#include "ir_hierarchical_visitor.h"
#include "program/hash_table.h"
#include "glsl_types.h"

class ir_validate : public ir_hierarchical_visitor {
public:
   ir_validate()
   {
      this->ht = hash_table_ctor(0, hash_table_pointer_hash,
				 hash_table_pointer_compare);

      this->current_function = NULL;

      this->callback = ir_validate::validate_ir;
      this->data = ht;
   }

   ~ir_validate()
   {
      hash_table_dtor(this->ht);
   }

   virtual ir_visitor_status visit(ir_variable *v);
   virtual ir_visitor_status visit(ir_dereference_variable *ir);
   virtual ir_visitor_status visit(ir_if *ir);

   virtual ir_visitor_status visit_leave(ir_loop *ir);
   virtual ir_visitor_status visit_enter(ir_function *ir);
   virtual ir_visitor_status visit_leave(ir_function *ir);
   virtual ir_visitor_status visit_enter(ir_function_signature *ir);

   virtual ir_visitor_status visit_leave(ir_expression *ir);

   virtual ir_visitor_status visit_enter(ir_assignment *ir);

   static void validate_ir(ir_instruction *ir, void *data);

   ir_function *current_function;

   struct hash_table *ht;
};

ir_visitor_status
ir_validate::visit(ir_dereference_variable *ir)
{
   if ((ir->var == NULL) || (ir->var->as_variable() == NULL)) {
      printf("ir_dereference_variable @ %p does not specify a variable %p\n",
	     (void *) ir, (void *) ir->var);
      abort();
   }

   if (hash_table_find(ht, ir->var) == NULL) {
      printf("ir_dereference_variable @ %p specifies undeclared variable "
	     "`%s' @ %p\n",
	     (void *) ir, ir->var->name, (void *) ir->var);
      abort();
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit(ir_if *ir)
{
   if (ir->condition->type != glsl_type::bool_type) {
      printf("ir_if condition %s type instead of bool.\n",
	     ir->condition->type->name);
      ir->print();
      printf("\n");
      abort();
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_loop *ir)
{
   if (ir->counter != NULL) {
      if ((ir->from == NULL) || (ir->from == NULL) || (ir->increment == NULL)) {
	 printf("ir_loop has invalid loop controls:\n"
		"    counter:   %p\n"
		"    from:      %p\n"
		"    to:        %p\n"
		"    increment: %p\n",
		ir->counter, ir->from, ir->to, ir->increment);
	 abort();
      }

      if ((ir->cmp < ir_binop_less) || (ir->cmp > ir_binop_nequal)) {
	 printf("ir_loop has invalid comparitor %d\n", ir->cmp);
	 abort();
      }
   } else {
      if ((ir->from != NULL) || (ir->from != NULL) || (ir->increment != NULL)) {
	 printf("ir_loop has invalid loop controls:\n"
		"    counter:   %p\n"
		"    from:      %p\n"
		"    to:        %p\n"
		"    increment: %p\n",
		ir->counter, ir->from, ir->to, ir->increment);
	 abort();
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_function *ir)
{
   /* Function definitions cannot be nested.
    */
   if (this->current_function != NULL) {
      printf("Function definition nested inside another function "
	     "definition:\n");
      printf("%s %p inside %s %p\n",
	     ir->name, (void *) ir,
	     this->current_function->name, (void *) this->current_function);
      abort();
   }

   /* Store the current function hierarchy being traversed.  This is used
    * by the function signature visitor to ensure that the signatures are
    * linked with the correct functions.
    */
   this->current_function = ir;

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_function *ir)
{
   assert(talloc_parent(ir->name) == ir);

   this->current_function = NULL;
   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_function_signature *ir)
{
   if (this->current_function != ir->function()) {
      printf("Function signature nested inside wrong function "
	     "definition:\n");
      printf("%p inside %s %p instead of %s %p\n",
	     (void *) ir,
	     this->current_function->name, (void *) this->current_function,
	     ir->function_name(), (void *) ir->function());
      abort();
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_expression *ir)
{
   switch (ir->operation) {
   case ir_unop_bit_not:
      assert(ir->operands[0]->type == ir->type);
      break;
   case ir_unop_logic_not:
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      break;

   case ir_unop_neg:
   case ir_unop_abs:
   case ir_unop_sign:
   case ir_unop_rcp:
   case ir_unop_rsq:
   case ir_unop_sqrt:
      assert(ir->type == ir->operands[0]->type);
      break;

   case ir_unop_exp:
   case ir_unop_log:
   case ir_unop_exp2:
   case ir_unop_log2:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type == ir->operands[0]->type);
      break;

   case ir_unop_f2i:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type->base_type == GLSL_TYPE_INT);
      break;
   case ir_unop_i2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;
   case ir_unop_f2b:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      break;
   case ir_unop_b2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;
   case ir_unop_i2b:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      break;
   case ir_unop_b2i:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type->base_type == GLSL_TYPE_INT);
      break;
   case ir_unop_u2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_UINT);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;

   case ir_unop_any:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type == glsl_type::bool_type);
      break;

   case ir_unop_trunc:
   case ir_unop_ceil:
   case ir_unop_floor:
   case ir_unop_fract:
   case ir_unop_sin:
   case ir_unop_cos:
   case ir_unop_dFdx:
   case ir_unop_dFdy:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->operands[0]->type == ir->type);
      break;

   case ir_binop_add:
   case ir_binop_sub:
   case ir_binop_mul:
   case ir_binop_div:
   case ir_binop_mod:
   case ir_binop_min:
   case ir_binop_max:
   case ir_binop_pow:
      if (ir->operands[0]->type->is_scalar())
	 assert(ir->operands[1]->type == ir->type);
      else if (ir->operands[1]->type->is_scalar())
	 assert(ir->operands[0]->type == ir->type);
      else if (ir->operands[0]->type->is_vector() &&
	       ir->operands[1]->type->is_vector()) {
	 assert(ir->operands[0]->type == ir->operands[1]->type);
	 assert(ir->operands[0]->type == ir->type);
      }
      break;
   case ir_binop_less:
   case ir_binop_greater:
   case ir_binop_lequal:
   case ir_binop_gequal:
      /* GLSL < > <= >= operators take scalar floats/ints, but in the
       * IR we may want to do them for vectors instead to support the
       * lessEqual() and friends builtins.
       */
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_equal:
   case ir_binop_nequal:
      /* GLSL == and != operate on vectors and return a bool, and the
       * IR matches that.  We may want to switch up the IR to work on
       * vectors and return a bvec and make the operators break down
       * to ANDing/ORing the results of the vector comparison.
       */
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_lshift:
   case ir_binop_rshift:
   case ir_binop_bit_and:
   case ir_binop_bit_xor:
   case ir_binop_bit_or:
      assert(ir->operands[0]->type == ir->operands[1]->type);
      assert(ir->type == ir->operands[0]->type);
      assert(ir->type->base_type == GLSL_TYPE_INT ||
	     ir->type->base_type == GLSL_TYPE_UINT);
      break;

   case ir_binop_logic_and:
   case ir_binop_logic_xor:
   case ir_binop_logic_or:
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == glsl_type::bool_type);
      assert(ir->operands[1]->type == glsl_type::bool_type);
      break;

   case ir_binop_dot:
      assert(ir->type == glsl_type::float_type);
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_cross:
      assert(ir->operands[0]->type == glsl_type::vec3_type);
      assert(ir->operands[1]->type == glsl_type::vec3_type);
      assert(ir->type == glsl_type::vec3_type);
      break;
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit(ir_variable *ir)
{
   /* An ir_variable is the one thing that can (and will) appear multiple times
    * in an IR tree.  It is added to the hashtable so that it can be used
    * in the ir_dereference_variable handler to ensure that a variable is
    * declared before it is dereferenced.
    */
   if (ir->name)
      assert(talloc_parent(ir->name) == ir);

   hash_table_insert(ht, ir, ir);
   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_assignment *ir)
{
   const ir_dereference *const lhs = ir->lhs;
   if (lhs->type->is_scalar() || lhs->type->is_vector()) {
      if (ir->write_mask == 0) {
	 printf("Assignment LHS is %s, but write mask is 0:\n",
		lhs->type->is_scalar() ? "scalar" : "vector");
	 ir->print();
	 abort();
      }

      /* Mask of fields that do not exist in the destination.  These should
       * not be written by the assignment.
       */
      const unsigned invalid_mask = ~((1U << lhs->type->components()) - 1);

      if ((invalid_mask & ir->write_mask) != 0) {
	 printf("Assignment write mask enables invalid components for "
		"type %s:\n", lhs->type->name);
	 ir->print();
	 abort();
      }
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

void
ir_validate::validate_ir(ir_instruction *ir, void *data)
{
   struct hash_table *ht = (struct hash_table *) data;

   if (hash_table_find(ht, ir)) {
      printf("Instruction node present twice in ir tree:\n");
      ir->print();
      printf("\n");
      abort();
   }
   hash_table_insert(ht, ir, ir);
}

void
check_node_type(ir_instruction *ir, void *data)
{
   (void) data;

   if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) {
      printf("Instruction node with unset type\n");
      ir->print(); printf("\n");
   }
   assert(ir->type != glsl_type::error_type);
}

void
validate_ir_tree(exec_list *instructions)
{
   ir_validate v;

   v.run(instructions);

   foreach_iter(exec_list_iterator, iter, *instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();

      visit_tree(ir, check_node_type, NULL);
   }
}
<commit_msg>ir_validate: Ensure ir_binop_dot is only used on vector types.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_validate.cpp
 *
 * Attempts to verify that various invariants of the IR tree are true.
 *
 * In particular, at the moment it makes sure that no single
 * ir_instruction node except for ir_variable appears multiple times
 * in the ir tree.  ir_variable does appear multiple times: Once as a
 * declaration in an exec_list, and multiple times as the endpoint of
 * a dereference chain.
 */

#include <inttypes.h>
#include "ir.h"
#include "ir_hierarchical_visitor.h"
#include "program/hash_table.h"
#include "glsl_types.h"

class ir_validate : public ir_hierarchical_visitor {
public:
   ir_validate()
   {
      this->ht = hash_table_ctor(0, hash_table_pointer_hash,
				 hash_table_pointer_compare);

      this->current_function = NULL;

      this->callback = ir_validate::validate_ir;
      this->data = ht;
   }

   ~ir_validate()
   {
      hash_table_dtor(this->ht);
   }

   virtual ir_visitor_status visit(ir_variable *v);
   virtual ir_visitor_status visit(ir_dereference_variable *ir);
   virtual ir_visitor_status visit(ir_if *ir);

   virtual ir_visitor_status visit_leave(ir_loop *ir);
   virtual ir_visitor_status visit_enter(ir_function *ir);
   virtual ir_visitor_status visit_leave(ir_function *ir);
   virtual ir_visitor_status visit_enter(ir_function_signature *ir);

   virtual ir_visitor_status visit_leave(ir_expression *ir);

   virtual ir_visitor_status visit_enter(ir_assignment *ir);

   static void validate_ir(ir_instruction *ir, void *data);

   ir_function *current_function;

   struct hash_table *ht;
};

ir_visitor_status
ir_validate::visit(ir_dereference_variable *ir)
{
   if ((ir->var == NULL) || (ir->var->as_variable() == NULL)) {
      printf("ir_dereference_variable @ %p does not specify a variable %p\n",
	     (void *) ir, (void *) ir->var);
      abort();
   }

   if (hash_table_find(ht, ir->var) == NULL) {
      printf("ir_dereference_variable @ %p specifies undeclared variable "
	     "`%s' @ %p\n",
	     (void *) ir, ir->var->name, (void *) ir->var);
      abort();
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit(ir_if *ir)
{
   if (ir->condition->type != glsl_type::bool_type) {
      printf("ir_if condition %s type instead of bool.\n",
	     ir->condition->type->name);
      ir->print();
      printf("\n");
      abort();
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_loop *ir)
{
   if (ir->counter != NULL) {
      if ((ir->from == NULL) || (ir->from == NULL) || (ir->increment == NULL)) {
	 printf("ir_loop has invalid loop controls:\n"
		"    counter:   %p\n"
		"    from:      %p\n"
		"    to:        %p\n"
		"    increment: %p\n",
		ir->counter, ir->from, ir->to, ir->increment);
	 abort();
      }

      if ((ir->cmp < ir_binop_less) || (ir->cmp > ir_binop_nequal)) {
	 printf("ir_loop has invalid comparitor %d\n", ir->cmp);
	 abort();
      }
   } else {
      if ((ir->from != NULL) || (ir->from != NULL) || (ir->increment != NULL)) {
	 printf("ir_loop has invalid loop controls:\n"
		"    counter:   %p\n"
		"    from:      %p\n"
		"    to:        %p\n"
		"    increment: %p\n",
		ir->counter, ir->from, ir->to, ir->increment);
	 abort();
      }
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_function *ir)
{
   /* Function definitions cannot be nested.
    */
   if (this->current_function != NULL) {
      printf("Function definition nested inside another function "
	     "definition:\n");
      printf("%s %p inside %s %p\n",
	     ir->name, (void *) ir,
	     this->current_function->name, (void *) this->current_function);
      abort();
   }

   /* Store the current function hierarchy being traversed.  This is used
    * by the function signature visitor to ensure that the signatures are
    * linked with the correct functions.
    */
   this->current_function = ir;

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_function *ir)
{
   assert(talloc_parent(ir->name) == ir);

   this->current_function = NULL;
   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_function_signature *ir)
{
   if (this->current_function != ir->function()) {
      printf("Function signature nested inside wrong function "
	     "definition:\n");
      printf("%p inside %s %p instead of %s %p\n",
	     (void *) ir,
	     this->current_function->name, (void *) this->current_function,
	     ir->function_name(), (void *) ir->function());
      abort();
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

ir_visitor_status
ir_validate::visit_leave(ir_expression *ir)
{
   switch (ir->operation) {
   case ir_unop_bit_not:
      assert(ir->operands[0]->type == ir->type);
      break;
   case ir_unop_logic_not:
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      break;

   case ir_unop_neg:
   case ir_unop_abs:
   case ir_unop_sign:
   case ir_unop_rcp:
   case ir_unop_rsq:
   case ir_unop_sqrt:
      assert(ir->type == ir->operands[0]->type);
      break;

   case ir_unop_exp:
   case ir_unop_log:
   case ir_unop_exp2:
   case ir_unop_log2:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type == ir->operands[0]->type);
      break;

   case ir_unop_f2i:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type->base_type == GLSL_TYPE_INT);
      break;
   case ir_unop_i2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;
   case ir_unop_f2b:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      break;
   case ir_unop_b2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;
   case ir_unop_i2b:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_INT);
      assert(ir->type->base_type == GLSL_TYPE_BOOL);
      break;
   case ir_unop_b2i:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type->base_type == GLSL_TYPE_INT);
      break;
   case ir_unop_u2f:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_UINT);
      assert(ir->type->base_type == GLSL_TYPE_FLOAT);
      break;

   case ir_unop_any:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_BOOL);
      assert(ir->type == glsl_type::bool_type);
      break;

   case ir_unop_trunc:
   case ir_unop_ceil:
   case ir_unop_floor:
   case ir_unop_fract:
   case ir_unop_sin:
   case ir_unop_cos:
   case ir_unop_dFdx:
   case ir_unop_dFdy:
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->operands[0]->type == ir->type);
      break;

   case ir_binop_add:
   case ir_binop_sub:
   case ir_binop_mul:
   case ir_binop_div:
   case ir_binop_mod:
   case ir_binop_min:
   case ir_binop_max:
   case ir_binop_pow:
      if (ir->operands[0]->type->is_scalar())
	 assert(ir->operands[1]->type == ir->type);
      else if (ir->operands[1]->type->is_scalar())
	 assert(ir->operands[0]->type == ir->type);
      else if (ir->operands[0]->type->is_vector() &&
	       ir->operands[1]->type->is_vector()) {
	 assert(ir->operands[0]->type == ir->operands[1]->type);
	 assert(ir->operands[0]->type == ir->type);
      }
      break;
   case ir_binop_less:
   case ir_binop_greater:
   case ir_binop_lequal:
   case ir_binop_gequal:
      /* GLSL < > <= >= operators take scalar floats/ints, but in the
       * IR we may want to do them for vectors instead to support the
       * lessEqual() and friends builtins.
       */
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_equal:
   case ir_binop_nequal:
      /* GLSL == and != operate on vectors and return a bool, and the
       * IR matches that.  We may want to switch up the IR to work on
       * vectors and return a bvec and make the operators break down
       * to ANDing/ORing the results of the vector comparison.
       */
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_lshift:
   case ir_binop_rshift:
   case ir_binop_bit_and:
   case ir_binop_bit_xor:
   case ir_binop_bit_or:
      assert(ir->operands[0]->type == ir->operands[1]->type);
      assert(ir->type == ir->operands[0]->type);
      assert(ir->type->base_type == GLSL_TYPE_INT ||
	     ir->type->base_type == GLSL_TYPE_UINT);
      break;

   case ir_binop_logic_and:
   case ir_binop_logic_xor:
   case ir_binop_logic_or:
      assert(ir->type == glsl_type::bool_type);
      assert(ir->operands[0]->type == glsl_type::bool_type);
      assert(ir->operands[1]->type == glsl_type::bool_type);
      break;

   case ir_binop_dot:
      assert(ir->type == glsl_type::float_type);
      assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
      assert(ir->operands[0]->type->is_vector());
      assert(ir->operands[0]->type == ir->operands[1]->type);
      break;

   case ir_binop_cross:
      assert(ir->operands[0]->type == glsl_type::vec3_type);
      assert(ir->operands[1]->type == glsl_type::vec3_type);
      assert(ir->type == glsl_type::vec3_type);
      break;
   }

   return visit_continue;
}

ir_visitor_status
ir_validate::visit(ir_variable *ir)
{
   /* An ir_variable is the one thing that can (and will) appear multiple times
    * in an IR tree.  It is added to the hashtable so that it can be used
    * in the ir_dereference_variable handler to ensure that a variable is
    * declared before it is dereferenced.
    */
   if (ir->name)
      assert(talloc_parent(ir->name) == ir);

   hash_table_insert(ht, ir, ir);
   return visit_continue;
}

ir_visitor_status
ir_validate::visit_enter(ir_assignment *ir)
{
   const ir_dereference *const lhs = ir->lhs;
   if (lhs->type->is_scalar() || lhs->type->is_vector()) {
      if (ir->write_mask == 0) {
	 printf("Assignment LHS is %s, but write mask is 0:\n",
		lhs->type->is_scalar() ? "scalar" : "vector");
	 ir->print();
	 abort();
      }

      /* Mask of fields that do not exist in the destination.  These should
       * not be written by the assignment.
       */
      const unsigned invalid_mask = ~((1U << lhs->type->components()) - 1);

      if ((invalid_mask & ir->write_mask) != 0) {
	 printf("Assignment write mask enables invalid components for "
		"type %s:\n", lhs->type->name);
	 ir->print();
	 abort();
      }
   }

   this->validate_ir(ir, this->data);

   return visit_continue;
}

void
ir_validate::validate_ir(ir_instruction *ir, void *data)
{
   struct hash_table *ht = (struct hash_table *) data;

   if (hash_table_find(ht, ir)) {
      printf("Instruction node present twice in ir tree:\n");
      ir->print();
      printf("\n");
      abort();
   }
   hash_table_insert(ht, ir, ir);
}

void
check_node_type(ir_instruction *ir, void *data)
{
   (void) data;

   if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) {
      printf("Instruction node with unset type\n");
      ir->print(); printf("\n");
   }
   assert(ir->type != glsl_type::error_type);
}

void
validate_ir_tree(exec_list *instructions)
{
   ir_validate v;

   v.run(instructions);

   foreach_iter(exec_list_iterator, iter, *instructions) {
      ir_instruction *ir = (ir_instruction *)iter.get();

      visit_tree(ir, check_node_type, NULL);
   }
}
<|endoftext|>