Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/* "True" vs "False" vs "Unknown".
   Copyright (C) 2019-2020 Free Software Foundation, Inc.
   Contributed by David Malcolm <dmalcolm@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tristate.h"
#include "selftest.h"

const char *
tristate::as_string () const
{
  switch (m_value)
    {
    default:
      gcc_unreachable ();
    case TS_UNKNOWN:
      return "UNKNOWN";
    case TS_TRUE:
      return "TRUE";
    case TS_FALSE:
      return "FALSE";
    }
}

tristate
tristate::not_ () const
{
  switch (m_value)
    {
    default:
      gcc_unreachable ();
    case TS_UNKNOWN:
      return tristate (TS_UNKNOWN);
    case TS_TRUE:
      return tristate (TS_FALSE);
    case TS_FALSE:
      return tristate (TS_TRUE);
    }
}

tristate
tristate::or_ (tristate other) const
{
  switch (m_value)
    {
    default:
      gcc_unreachable ();
    case TS_UNKNOWN:
      if (other.is_true ())
	return tristate (TS_TRUE);
      else
	return tristate (TS_UNKNOWN);
    case TS_FALSE:
      return other;
    case TS_TRUE:
      return tristate (TS_TRUE);
    }
}

tristate
tristate::and_ (tristate other) const
{
  switch (m_value)
    {
    default:
      gcc_unreachable ();
    case TS_UNKNOWN:
      if (other.is_false ())
	return tristate (TS_FALSE);
      else
	return tristate (TS_UNKNOWN);
    case TS_TRUE:
      return other;
    case TS_FALSE:
      return tristate (TS_FALSE);
    }
}

#if CHECKING_P

namespace selftest {

#define ASSERT_TRISTATE_TRUE(TRISTATE) \
  SELFTEST_BEGIN_STMT					\
  ASSERT_EQ (TRISTATE, tristate (tristate::TS_TRUE));	\
  SELFTEST_END_STMT

#define ASSERT_TRISTATE_FALSE(TRISTATE) \
  SELFTEST_BEGIN_STMT					\
  ASSERT_EQ (TRISTATE, tristate (tristate::TS_FALSE));	\
  SELFTEST_END_STMT

#define ASSERT_TRISTATE_UNKNOWN(TRISTATE) \
  SELFTEST_BEGIN_STMT						\
  ASSERT_EQ (TRISTATE, tristate (tristate::TS_UNKNOWN));	\
  SELFTEST_END_STMT

/* Test tristate's ctors, along with is_*, as_string, operator==, and
   operator!=.  */

static void
test_ctors ()
{
  tristate u (tristate::TS_UNKNOWN);
  ASSERT_FALSE (u.is_known ());
  ASSERT_FALSE (u.is_true ());
  ASSERT_FALSE (u.is_false ());
  ASSERT_STREQ (u.as_string (), "UNKNOWN");

  tristate t (tristate::TS_TRUE);
  ASSERT_TRUE (t.is_known ());
  ASSERT_TRUE (t.is_true ());
  ASSERT_FALSE (t.is_false ());
  ASSERT_STREQ (t.as_string (), "TRUE");

  tristate f (tristate::TS_FALSE);
  ASSERT_TRUE (f.is_known ());
  ASSERT_FALSE (f.is_true ());
  ASSERT_TRUE (f.is_false ());
  ASSERT_STREQ (f.as_string (), "FALSE");

  ASSERT_EQ (u, u);
  ASSERT_EQ (t, t);
  ASSERT_EQ (f, f);
  ASSERT_NE (u, t);
  ASSERT_NE (u, f);
  ASSERT_NE (t, f);

  tristate t2 (true);
  ASSERT_TRUE (t2.is_true ());
  ASSERT_EQ (t, t2);

  tristate f2 (false);
  ASSERT_TRUE (f2.is_false ());
  ASSERT_EQ (f, f2);

  tristate u2 (tristate::unknown ());
  ASSERT_TRUE (!u2.is_known ());
  ASSERT_EQ (u, u2);
}

/* Test && on tristate instances.  */

static void
test_and ()
{
  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () && tristate::unknown ());

  ASSERT_TRISTATE_FALSE (tristate (false) && tristate (false));
  ASSERT_TRISTATE_FALSE (tristate (false) && tristate (true));
  ASSERT_TRISTATE_FALSE (tristate (true) && tristate (false));
  ASSERT_TRISTATE_TRUE (tristate (true) && tristate (true));

  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () && tristate (true));
  ASSERT_TRISTATE_UNKNOWN (tristate (true) && tristate::unknown ());

  ASSERT_TRISTATE_FALSE (tristate::unknown () && tristate (false));
  ASSERT_TRISTATE_FALSE (tristate (false) && tristate::unknown ());
}

/* Test || on tristate instances.  */

static void
test_or ()
{
  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () || tristate::unknown ());

  ASSERT_TRISTATE_FALSE (tristate (false) || tristate (false));
  ASSERT_TRISTATE_TRUE (tristate (false) || tristate (true));
  ASSERT_TRISTATE_TRUE (tristate (true) || tristate (false));
  ASSERT_TRISTATE_TRUE (tristate (true) || tristate (true));

  ASSERT_TRISTATE_TRUE (tristate::unknown () || tristate (true));
  ASSERT_TRISTATE_TRUE (tristate (true) || tristate::unknown ());

  ASSERT_TRISTATE_UNKNOWN (tristate::unknown () || tristate (false));
  ASSERT_TRISTATE_UNKNOWN (tristate (false) || tristate::unknown ());
}

/* Test ! on tristate instances.  */

static void
test_not ()
{
  ASSERT_TRISTATE_UNKNOWN (!tristate::unknown ());
  ASSERT_TRISTATE_FALSE (!tristate (true));
  ASSERT_TRISTATE_TRUE (!tristate (false));
}

/* Run all of the selftests within this file.  */

void
tristate_cc_tests ()
{
  test_ctors ();
  test_and ();
  test_or ();
  test_not ();
}

} // namespace selftest

#endif /* CHECKING_P */